`
原来我就是麦兜
  • 浏览: 9797 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

[Java5新特性]反射

 
阅读更多

什么是反射机制

反射机制是Java 5版本提供的高级新特性,这种机制允许Java程序在运行状态中,对任意一个类都能知道该类的所有属性和方法;对任意一个对象,都能调用该对象的属性和方法。这种动态获取信息及动态调用对象的属性和方法的功能称之为Java的反射机制。

在我们编写Java类文件时,真正运行的是编译之后的“.class”文件。而“.class”文件在运行时,被加载到内存后,都是一个Class类的对象。我们可以通过Java 5提供的反射机制获取到该类的构造器、方法及成员变量等。

简单来说,Java的反射机制中提供了Class类、Constructor、Method及Field等,Class类就是类的元神,Constructor就是构造器的元神,Method就是方法的元神,Field就是成员变量的元神。

反射中的Class类

Class类是Java 5提供一个新类型,就叫做类类型。如何可以获取一个Class类型的对象呢?传统方式就是利用new Class()方式,但Java 5提供不同的方式。参看以下代码:

public class Demo {
    @Test
    public void demo() throws ClassNotFoundException {

        // 第一种方式:类名.class
        Class c1 = int.class;
        Class c2 = int[].class;

        // 第二种方式:对象.getClass()
        Class c3 = "hello".getClass();

        // 第三种方式:Class.forName("类全名")
        Class c4 = Class.forName("app.java.reflect.Demo");
    }
}

通过以上代码我们可以了解,获取Class实例的方式有三种:

  • 类名.class,例如:Class c1 = Object.class;
  • 对象.getClass(),例如:Class c2 = “Hello”.getClass();
  • Class.forName(“类全名”),例如:Class c1 = Class.forName(“app.java.reflect.Demo”);

获取到Class类实例之后,有什么具体用途呢?第一,我们可以通过Class类实例的getName()和getSimpleName()方法,获取到对应类的全类名或类名。

public class Demo {
    @Test
    public void demo() throws ClassNotFoundException {
        Class c1 = "hello".getClass();
        // java.lang.String
        System.out.println(c1.getName());

        Class c2 = int[].class;
        // [I:"["表示数组,"I"表示int类型
        System.out.println(c2.getName());
        // int[]
        System.out.println(c2.getSimpleName());
    }
}

第二,我们可以通过Class类实例的getSuperclass()方法,获取到对应类的完整继承链关系。

public class Demo {
    @Test
    public void demo() throws ClassNotFoundException {
        Class c = java.awt.Frame.class;
        while (c.getSuperclass() != null) {
            System.out.println(c.getSuperclass().getName());
            c = c.getSuperclass();
        }
    }
}

第三,我们可以通过反射机制来创建对象。

public class Demo {
    @Test
    public void demo() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String className = "app.java.reflect.User";
        Class c = Class.forName(className);
        User user = (User) c.newInstance();
        user.setUsername("king");
        System.out.println(user.getUsername());
    }
}
class User{
    private String username;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    private String password;
}

反射中的Constructor

传统Java方式获取类的实例,基本都是通过构造器来实现,反射机制中的Class类同样具有构造器。那反射机制中Class类的构造器如何获得呢?我们来看以下代码:

public class Demo {

    @Test
    public void demo() throws Exception{
        Class<User> c = User.class;

        // 获取c类型中所有public构造器
        Constructor[] constructors1 = c.getConstructors();
        // 获取c类型中所有构造器
        Constructor[] constructors2 = c.getDeclaredConstructors();

        System.out.println(constructors1.length);
        System.out.println(constructors2.length);

        // 获取没有参数的public构造器
        Constructor con1 = c.getConstructor();
        // 获取参数类型依次为String.class,String.class的public构造器
        Constructor con2 = c.getConstructor(String.class,String.class);
        // 获取参数类型为String.class的构造器
        Constructor con3 = c.getDeclaredConstructor(String.class);
    }
}

通过上面的代码,我们可以知道:在获取到Class类实例后,有四种方式可以获取到对应的构造器。

  • getConstructors()方法:获取Class类所有的public构造器,其中包含没有参数和有参数的。
  • getDeclaredConstructors()方法:获取Class类所有的构造器,其中包含由public、private和protected修饰符的。
  • getConstructor()方法:获取具体的public修饰构造器,参数表示是否具有参数的构造器。
  • getDeclaredConstructor()方法:获取具体的构造器,其中包含由public、private和protected修饰符的。

我们得到Class类型的构造器之后,又会有什么样的用途呢?第一,可以通过构造器来创建实例对象。

public class Demo {
    @Test
    public void demo() throws Exception{
        Class<User> c = User.class;
        Constructor<User> constructor = c.getConstructor(String.class,String.class);
        User user = constructor.newInstance("king","123");
        System.out.println(user);
    }
}

第二,我们可以构造器来打印指定类型的所有构造器,以及参数类型。

public class Demo {
    @Test
    public void demo() throws Exception{
        Class<String> c = String.class;
        Constructor[] constructors = c.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.print(constructor.getDeclaringClass().getSimpleName() + "(");
            Class[] classes = constructor.getParameterTypes();
            for (int i = 0; i < classes.length; i++) {
                System.out.print(classes[i].getSimpleName());
                if (i < classes.length - 1) {
                    System.out.print(", ");
                }
            }
            System.out.println(")");
        }
    }
}

反射中的Method

与Class类的构造器类似的就是方法,我们首先讨论如何获取方法。

public class Demo {
    @Test
    public void demo() throws Exception{
        Class<User> c = User.class;

        // 获取本类和父类中的所有public方法
        Method[] ms1 = c.getMethods();
        System.out.println(ms1.length);

        // 获取本类中所有方法
        Method[] ms2 = c.getDeclaredMethods();
        System.out.println(ms2.length);

        // 获取本类或父类中名称为setUsername,参数类型为String的public方法
        Method m1 = c.getMethod("setUsername", String.class);

        // 获取本类中声明的名称为toString的,没有参数的方法,它可以是任何访问级别,但它不能是父类中的方法
        Method m2 = c.getDeclaredMethod("toString");
    }
}

通过上面的代码,我们可以知道:在获取到Class类实例后,有四种方式可以获取到对应的方法。

  • getMethods()方法:获取Class类及父类的所有public方法。
  • getDeclaredMethods()方法:获取Class类的所有方法,其中包含由public、private修饰符的。
  • getMethod()方法:获取Class类及父类中具体的public方法。
  • getDeclaredMethod()方法:获取Class类中具体的方法,其中包含由public、private修饰符的。但不能是父类中的方法。

下面我们来看一个利用Class类实例方法的练习。

public class Demo {
    @Test
    public void demo() throws Exception{
        Class<User> c = User.class;

        Method method = c.getMethod("setUsername", String.class);

        Object object = c.newInstance();

        method.invoke(object, "king");

        System.out.println(object);
    }
}

反射中的Field

与Class类的构造器和方法类似的就是成员变量,我们首先讨论如何获取成员变量。

public class Demo {
    @Test
    public void demo() throws Exception{
        Class<User> c = User.class;

        // 获取本类和父类中的所有public成员变量
        Field[] fields1 = c.getFields();
        System.out.println(fields1.length);

        // 获取本类中所有成员变量
        Field[] fields2 = c.getDeclaredFields();
        System.out.println(fields2.length);

        // 获取本类或父类中名称为password,参数类型为String的public成员变量
        Field field1 = c.getField("password");

        // 获取本类中名称为password的成员变量,但它不能是父类中的成员变量
        Field field2 = c.getDeclaredField("password");
    }
}

通过上面的代码,我们可以知道:在获取到Class类实例后,有四种方式可以获取到对应的成员变量。

  • getFields()方法:获取Class类及父类的所有public成员变量。
  • getDeclaredFields()方法:获取Class类的所有成员变量,其中包含由public、private修饰符的。
  • getField()方法:获取Class类及父类的具体成员变量。
  • getDeclaredField()方法:获取Class类的具体成员变量,其中包含由public、private修饰符的。但不能是父类中的方法。

获取到Class类的成员变量之后,我们可以进行设置和获取操作。

public class Demo {
    @Test
    public void demo() throws Exception{
        Class<User> c = User.class;

        Field field = c.getField("password");

        Object object = c.newInstance();

        field.set(object, "123");
        System.out.println(field.get(object));
    }
}

需要注意的是这里只能设置和获取修饰符为public的成员变量,不能操作修饰符为private的成员变量。

AccessibleObject

AccessibleObject类是Constructor、Method和Field三个类的父类。AccessibleObject类的常用方法有以下几种:

  • isAccessible()方法:判断当前成员是否可访问。
  • setAccessible()方法:设置当前成员是否可访问。

当Class类中的构造器、方法和成员变量是私有的时候,如果我们想反射操作的话,就必须先调用setAccessible(true)方法。

public class Demo {
    @Test
    public void demo() throws Exception{
        Class<User> c = User.class;

        Field field = c.getDeclaredField("username");

        Object object = c.newInstance();

        field.setAccessible(true);

        field.set(object, "king");

        System.out.println(field.get(object));
    }
}

转载说明:请注明作者及原文链接,谢谢!

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
分享到:
评论

相关推荐

    基于java8新特性+反射机制实现list不同实体类互转.zip

    实现list不同泛型之间实体的互转,基于java8新特性+反射机制实现list不同实体类互转,将jdk8的流处理集合互转抽出来成一个工具类,实现lsit

    JAVA新特性--java反射、映射

    反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。在计算机科学领域,反射是指一类...

    Java反射与JDK新特性

    Java反射与JDK新特性

    java高级特性增强

    java多线程、反射、代理等基础知识详细介绍,通过此文档可快速进阶为中级工程师

    java注解、java反射机制 jdbc 封装

    该案例实现jdk1.5新特性:java注解和java反射机制加上jdbc API综合运用的一个案例,实现了数据库的简易封装,对想了解jdk的反射机制,注解有帮助

    详解Java高级特性之反射

    主要介绍了Java高级特性之反射的相关知识,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下

    java高级特性整理资料(反射+并发+jvm)

    包含java三大高级特性的文档,《Java Reflection in Action》、《JAVA并发编程实战》、《JVM调优总结》、《深入理解Java虚拟机JVM高级特性与最佳实践》、《concurrent programming in java》,适合想深入java技术的...

    候捷谈Java反射机制

    候捷谈Java反射机制 有助深入理解Java新特性

    《Java 核心技术 卷I 》第12版,涵盖Java17新特性(英文版)

    着力让读者在充分理解Java语言和Java类库的基础上,灵活应用Java提供的高级特性,具体包括面向对象程序设计、反射与代理、接口与内部类、异常处理、泛型程序设计、集合框架、事件监听器模型、图形用户界面设计和...

    JAVA2 反射技术 pdf

    反射本身是JAVA 语言的特性,使JAVA 语言有一种在运行时态自“自观”的能力。而 其他面向对象的语言却没有类似的功能。

    新特性 反射技术

    泛型 --- 通用类型 由来 : java语言 开发者 一批C++ 工程师 ,在c++ 语法中 模板...JDK5 之前集合对象使用问题: 1、向集合添加任何类型对象 2、从集合取出对象时,数据类型丢失,使用与类型相关方法,强制类型转换

    Java核心技术 第12版 开发基础+高级特性 英文原版

    着力让读者在充分理解Java语言和Java类库的基础上,灵活应用Java提供的高级特性,具体包括面向对象程序设计、反射与代理、接口与内部类、异常处理、泛型程序设计、集合框架、事件监听器模型、图形用户界面设计和并发...

    Java Reflection (JAVA反射)

    Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。 JavaBean 是 reflection 的实际应用之...

    Java 高级特性.doc

    以上的一些程序代码均为张老师课堂即兴发挥所写,也可以看出,张老师对JAVA特性的深刻理解能力!现在说说我对这些程序代码的理解,说实话,才开始听张老师讲的时候,我感觉很模糊的,但是当我真正理解了之后,觉得...

    Java反射机制的缺点_尚硅谷_张晓飞

    Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature ...

    Java高级特性之反射机制实例详解

    主要介绍了Java高级特性之反射机制,结合实例形式详细分析了Java反射机制原理、功能、使用方法及相关操作注意事项,需要的朋友可以参考下

    尚硅谷_宋红康_第15章节练习_Java反射机制.doc

    ·基于JDK 11,将Java8、Java9、Java10、Java11新特性一网打尽 ·课程中,Eclipse和IDEA这两种企业一线开发环境都使用到了 3.技术讲解更深入、更全面: ·课程共30天,715个知识视频小节,涉及主流Java使用的...

    JDK5.0新特性 反射、枚举.rar

    jdk1.5以上版本中新增加的特性描述,带有代码例子让你很清晰的明白jdk的 常量 、枚举、 for each、反射等各种新的特性,相信需要的你,一定满足。

    Java反射技术详解及实例解析

    主要介绍了Java反射技术详解及实例解析,反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的。如果对JAVA感兴趣来可以学习一下

    Java SE完整版精品优质课件 自学入门必看的优秀Java基础知识培训教案 第13章_Java反射机制(共44页).pptx

    Java SE完整版精品优质课件 自学入门必看的优秀Java基础...第5章 高级类特性2 第6章 异常处理 第7章 Java集合 第8章 泛型 第9章 注解&枚举 第10章 IO 第11章 多线程 第12章 Java常用类 第13章 Java反射 第14章 网络编程

Global site tag (gtag.js) - Google Analytics