Java反射机制初探

栏目: Java · 发布时间: 6年前

内容简介:Java反射机制初探

最近和一位师兄交流了一下Java,真可谓是大有收获,让我好好的学习了一下javad的反射机制,同终于明白了spring等框架的一个基本实现的思想,那么今天就和大家分享一下 java 的反射机制。

反射,reflection,听其名就像照镜子一样,可以看见自己也可以看见别人的每一部分。在java语言中这是一个很重要的特性。下面是来自sun公司官网关于反射的介绍:

Reflection is a feature in the Java programming language. It allows an executing Java program to examine or "introspect" upon itself, and manipulate internal properties of the program. For example, it's possible for a Java class to obtain the names of all its members and display them.

The ability to examine and manipulate a Java class from within itself may not sound like very much, but in other programming languages this feature simply doesn't exist. For example, there is no way in a Pascal, C, or C++ program to obtain information about the functions defined within that program.

One tangible use of reflection is in JavaBeans, where software components can be manipulated visually via a builder tool. The tool uses reflection to obtain the properties of Java components (classes) as they are dynamically loaded.

那么解释一下就是,反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。这个能特定我们不常看到,但是在其他的比如C或者C++语言中很不就存在这个特性。一个常见的例子是在JavaBean中,一些组件可以通过一个构造器来操作。这个构造器就是用的反射在动态加载的时候来获取的java中类的属性的。

反射的前传:类类型   Class Class                                                                                                                                   

java中有一个类很特殊,就是Class类,很多朋友在写程序的时候有用过比如Apple.class来查看类型信息,大家就可以把它理解为封装了类的信息,很多解释说Class类没有构造器,其实是有的,只不过它的构造方法是private的(构造函数还有private的??有,这样是为了禁止开发者去自己创建Class类的实例)。我们可以看一下JDK中源码:

Java反射机制初探

注释很明确的告诉了我们,这个类是有JVM来创建的,所以我们就不用麻烦了。如果我们拿到一个类的类型信息,就可以利用反射获取其各种成员以及方法了。(注:Class 从JDK1.5版本后就开始更多为泛型服务了)那么我们怎么拿到一个类型的信息呢?假设我们有一个Role类:


 1 package yui;
 2 
 3 /**
 4  * A base class having some attributes and methods
 5  * @author Octobershiner
 6  * @since 2012 3 17
 7  * 
 8  * */
10 public class Role {
11     
12     private String name;
13     private String type;
14     
15     // Constructors
16     public Role(){
17         System.out.println("Constructor Role() is invoking");
18     }
19     //私有构造器
20     private Role(String name){
21         this.name = name;
22         System.out.println("Constructor Role(String name) is invoking.");
23     }
24     
25     //get and set method
26     
27     public String getName() {
28         return name;
29     }
30     public void setName(String name) {
31         this.name = name;
32     }
33     public String getType() {
34         return type;
35     }
36     public void setType(String type) {
37         this.type = type;
38     }
39     
40     //override the toString method to show the class
41     @Override
42     public String toString(){
43         return "This is a role called "+this.name;
44     }
45     
46 }

在没有对象实例的时候,主要有两种办法。

        //获得类类型的两种方式
        Class cls1 = Role.class;
        Class cls2 = Class.forName("yui.Role");

注意第二种方式中,forName中的参数一定是完整的类名(包名+类名),并且这个方法需要捕获异常。现在得到cls1就可以创建一个Role类的实例了,利用Class的newInstance方法相当于调用类的默认的构造器

        Object o = cls1.newInstance(); //创建一个实例
        //Object o1 = new Role();   //与上面的方法等价

这样就创建了一个对象,缺点是我们只能利用默认构造函数,因为Class的newInstance是不接受参数的,后面会讲到可接受参数的newInstance,第二,如果类的构造函数是private的,比如Class,我们仍旧不能实例化其对象。

获取类的构造器                                                                                                                                                                 

首先介绍一下Constructor类,这个类用来封装反射得到的构造器,Class有四个方法来获得Constructor对象

  • public  Constructor <?>[] getConstructors()      返回类中所有的public构造器集合,默认构造器的下标为0
  • public  Constructor < T > getConstructor( Class <?>... parameterTypes)   返回指定public构造器,参数为构造器参数类型集合
  • public  Constructor <?>[] getDeclaredConstructors()  返回类中所有的构造器,包括私有
  • public  Constructor < T > getDeclaredConstructor( Class <?>... parameterTypes) 返回任意指定的构造器

从名字来看,还是很好懂的,带上Declared的都是获得所有的构造方法,包括私有,哈,这下我们就可以调用原本不允许调用的私有构造器了,看代码


 1         /**
 2          * 获取构造方法Constructor
 3          * getConstructor()  only for public 
 4          * getDeclaredConstructor()  global access all 
 5          * 
 6          * */
 7         
 8         //指定参数列表获取特定的方法
 9         Constructor con = cls1.getDeclaredConstructor(new Class[]{String.class});
10         con.setAccessible(true); //设置可访问的权限
11         Object obj = con.newInstance(new Object[]{"liyang"});
12         System.out.println(obj);  //打印一下这个对象的信息
13         
14 //获取所有的构造方法集合
15         Constructor con1[] = cls1.getDeclaredConstructors();
16         con1[1].setAccessible(true);
17         Object obj1 = con1[1].newInstance(new Object[]{"tom"});
18         System.out.println(obj1);

解释一下:第一个是获得一个指定的方法,我们指定了参数是一个String类型,第二段我们获得了所有的构造方法集合,并选取了其中一个创建了新的对象。注意这里Constructor的newInstance方法就可以设置参数了,与文章前面的同样的方法形成了对比。

注意,以上的四个方法全部需要抛出异常,当我们获得私有的方法的时候,要用setAccessible设置一下可访问的权限,例子中没有演示获取共有方法,那个比较简单,就不做介绍了,其实掌握了上面两个,其他就好理解了。

获取类的成员变量                                                                                                                                                                 

了解了构造器,其实你可以猜到成员变量的获取方法了,成员变量用Field类进行封装。

主要的方法非常的类似:

  • public  Field  getDeclaredField( String  name)  获取任意指定名字的成员
  • public  Field [] getDeclaredFields()             获取所有的成员变量
  • public  Field  getField( String  name)           获取任意public成员变量
  • public  Field [] getFields()                          获取所有的public成员变量

可以看出这些方法都是异曲同工的,好了直接看一下例子吧


1         /**
2          * 获取成员变量Field
3          * getField()
4          * getDeclaredField()
5          * */
6         Field mem = cls1.getDeclaredField("name");
7         mem.setAccessible(true);      
8         System.out.println("we get form field :"+mem.get(obj));
9          

这是在访问私有变量,什么私有变量也可以访问??是的。。。。

获取类的方法                                                                                                                                                                   

我觉得你已经可以帮我写这一段了,封装类的方法的类是Method.获取method也有四个方法,猜到了没??

  • public  Method [] getMethods()    获取所有的共有方法的集合
  • public  Method  getMethod( String  name, Class <?>... parameterTypes) 获取指定公有方法 参数1:方法名 参数2:参数类型集合  
  • public  Method [] getDeclaredMethods()  获取所有的方法
  • public  Method  getDeclaredMethod( String  name, Class <?>... parameterTypes) 获取任意指定方法

看下面的例子吧


1         /**
2          * 调用类的方法 Method
3          * getMethod()
4          * getDeclaredMethod()
5          * 
6          * */
7         Method f = cls1.getMethod("getName", null);
8         Object name = f.invoke(obj, null);
9         System.out.println("we invoke method : "+ name);

这个很简单吧,无参的时候我们只要传null就行了。

总结:                                                                                                                                                                                 

以上就是反射机制的简单的使用,显然学过spring的朋友一定明白了,为什么可以通过配置文件就可以让我们获得指定的方法和变量,在我们创建对象的时候都是通过传进string实现的,就好像你需要什么,我们去为你生产,还有我们一直在用Object,这就说明java语言的动态特性,依赖性大大的降低了。

Java学习交流QQ群:523047986  禁止闲聊,非喜勿进!


以上所述就是小编给大家介绍的《Java反射机制初探》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Developer's Guide to Social Programming

Developer's Guide to Social Programming

Mark D. Hawker / Addison-Wesley Professional / 2010-8-25 / USD 39.99

In The Developer's Guide to Social Programming, Mark Hawker shows developers how to build applications that integrate with the major social networking sites. Unlike competitive books that focus on a s......一起来看看 《Developer's Guide to Social Programming》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具