java.lang.reflect包的浅析

Object(源头)

Java的一切都是对象java

Object是反射的源头数组

Class是反射的导演函数

Class(导演)

在Java程序运行时,JVM会对全部的对象维护一个独一无二的类型标识,这就是Class对象。spa

Java的基本类型和关键字void也对应一个Class对象。
相同元素类型和维数的数组也对应一个Class对象。code

获取Class对象的几种方法:对象

  • 一个对象经过.class
  • 一个对象经过getClass方法
  • Class.forName(String)

Class对象有一些重要的方法:继承

  • getConstructor系列,用于获取构造方法
  • getField系列,用于获取属性
  • getMethod系列,用于获取方法

上述系列中包含Declared系列,能够获取当前对象的全部类型的反射(包含private),可是不能获取父类的反射接口

Constructor,Field,Method都是Class导演的三大利器,它们都位于java.lang.reflect包下,接下来将分别对这三大利器进行展现。get

Constructor

经过Class对象获取到的Constructor对象以后,最经常使用的操做就是用来实例化对象,调用newInstance方法便可。string

其实在Class对象中也有一个newInstance方法,也能够用来实例化对象,它们的区别是什么呢?

  • Class.newInstance() 只可以调用无参的构造函数,即默认的构造函数,要求被调用的构造函数是可见的,也即必须是public类型的;
  • Constructor.newInstance() 能够根据传入的参数,调用任意构造构造函数,在特定的状况下,能够调用私有的构造函数。

Demo

//Class.newInstance()
//只能调用public属性的无参构造函数 
A a = (A)Class.forName(A.class.getName()).newInstance();  

//Constructor.newInstance()
Class c= Class.forName(A.class.getName());
   
/*如下调用无参的、私有构造函数*/  
//得到无参构造
Constructor c0=c.getDeclaredConstructor();  
//设置无参构造是可访问的
c0.setAccessible(true);   
A a0=(A)c0.newInstance();
    
//调用无参构造函数,生成对象实例
/*如下调用带参的、私有构造函数*/   
Constructor c1=c.getDeclaredConstructor(new Class[]{int.class,int.class});   
c1.setAccessible(true);   
//调用有参构造函数,生成对象实例 
A a1=(A)c1.newInstance(new Object[]{5,6});   

复制代码

使用场景:

若是使用接口模式,使用new建立一个门的对象,Door door = new WoodenDoor(),当以换成其余门,须要修改代码,Door door = new OtherDoor()。因此咱们须要使用工厂模式,须要什么门就生产什么门,若是咱们再使用newInstance()方法来生产,则只须要修改配置文件便可。

Field

经过Class对象获取到的Field对象以后,咱们就能够自由的查看和设置对象的属性值。

关键方法:

  • get(Object object)查看特定对象的属性值
  • set(Object object, Object value)给特定对象设置属性
  • setAccessible(boolean flag)让private成员拥有public权限

Demo

//获取Class对象
Class aClass = MyObject.class
//经过Class对象获取Field对象
Field field = aClass.getDeclaredField("someField");
//设置可访问权限
field.setAccessible(true);

MyObject objectInstance = new MyObject();

//获取特定的对象的变量属性值
Object value = field.get(objectInstance);
//给特定对象的变量设置属性
field.set(objetInstance, value);
复制代码

由于Constructor,Field,Method都继承自AccessibleObject类,全部都拥有setAccessible方法,我的感受setAccessible有点窥探隐私的感受,哈哈哈,不知道Class导演怎么看。

Method

经过Class对象获取到的Method对象以后,想都不用想啊,获取一个方法不调用它干吗,因此咱们最经常使用的操做应该就是invoke方法。

相信你们对invoke并不会陌生,由于不少的异常,最后都会定位到invoke方法。

java.lang.NullPointerException
  at ......
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:497)
复制代码

invoke(Object receiver, Object… args),能够分为两种,传递receiver参数表示调用特定对象的方法,传null表示调用静态方法。

//获取一个方法名为doSomesthing,参数类型为String的方法
Method method = MyObject.class.getMethod("doSomething", String.class);

//调用静态的doSomesthing方法,传递参数"parameter-value1"
Object returnValue = method.invoke(null, "parameter-value1");
复制代码

最后说两句

本文只是对Clss对象以及reflect包下的对象进行简单的使用说明,关于反射的实现和原理,还有待于深刻研究。例如AccessibleObject对象以及对应相关xxxAccessor的实现。

相关文章
相关标签/搜索