Java 反射机制

  一、反射(Reflection)

  1、反射的概念

  反射是程序可以访问、检测和修改它本身状态或者行为的能力。通过反射,可以动态获取对象信息以及动态调用对象的方法。

  反射的基础是因为在运行状态中,JVM能够知道对象的所有属性和方法,并且能够调用它的任意一个方法或访问其任一属性。

  反射机制使得程序可以在运行时动态加载、查看和使用编译期间完全未知的类(对象)。

 

  2、反射机制提供的功能 

  • 运行时检测对象的类型;
  • 动态创建对象;
  • 减速对象的属性和方法;
  • 调用对象的任意方法;
  • 修改构造器、方法和属性的可见性;
  • 生成动态代理。

 

  3、反射的通常用途

  • 用于程序检查工具和调试器,它能获取程序在运行时刻的内部结构。只需要短短十几行代码,就可以遍历出对象所属类的结构,包括构造方法、声明的属性和定义的方法和修饰符等。
  • 在运行时刻与注解配合,动态改变对象的行为,例如,为特定对象添加日志、权限控制等操作。

 

  二、反射的实现

  1、反射机制的实现基于4个类,他们分别描述了一个类的各个组成部分。

  Class:代表运行时对象的类型信息,JVM使用这些类型信息确定方法。

  Constructor:表示类的构造器,即构造方法的描述类。

  Field:用来描述对象的属性集合。

  Method:用来描述方法。

  值得注意的是,通过上面方法访问反射机制创建的对象的私有构造器、属性、方法(少见)时,要先通过setAccessible(boolean T_or_F)方法修改访问权限!

 

  2、Class类——反射的基石

  Class类的对象用来描述运行时的类和接口,也用来表达enum、数组、基本数据类型以及关键词void。当一个类被加载或者当类加载器的defineClass()方法被调用,JVM就会自动产生一个Class对象。

  要查看任何类,都必须获得一个Class对象。然后由Class对象调用反射APIs。

  怎么获得Class对象?两种方式:

public class role{}
/*第一种*/
Class cls=Role.class;
/*第二种,forName()方法的参数必须是完整的路径类名(包名+类名),并且该方法需要捕获ClassNotFoundException异常。*/
Class cls=Class.forName(“cn.edu.ldu.javacourse.ch7.Role”);

   在得到Class的实例对象后就可以创建Role类的实例了,newInstance()只能调用类的默认构造器生成对象,即如果类的构造函数是私有的,仍旧不能进行实例化:

/*newInstance()方法的缺点是只能调用默认构造函数*/
Object o=cls.newInstance();

  Class的其他方法可以获取到类的构造方法、属性和成员方法:

  • getConstructor();
  • getField();
  • getMethod();

         同时这三个方法还有相应的getDeclaredxxx()版本,只获取该类自己声明的成员而不是从父类继承。

 

  3、Constructor类——获取构造器

  Constructor类是构造方法的描述类,Constructors对象可以通过Class对象的4个getXXX()方法获得(也可以获得构造器数组),这四个方法都需要抛出或捕获异常:

/*Class类有4个方法获得Constructors对象*/ 
Constructors con=cls.getXXXX();

/*获参数类型是String类型的构造方法*/ Constructor con=cls.getDeclaredConstructor(new Class[]{String.class});
/*然后设置所获得的构造器的访问权限*/ con. setAccessible(true); /*通过con的newInstance()方法创建新的对象*/ Object obj=con.newInstance (new Object[]{“Jerry”}); /*若要使用私有构造器,记得一定要修改访问权限*/
 

  

  4、Field类——获取成员变量

  成员变量用Field类进行封装,使用与上面相似。

/*返回了方法名*/
Field mem=cls.getDeclaredField("fieldName");
mem.setAccessible(true);
System.out.println("we get fields:"+mem.get(obj));

/*访问私有变量也要先改变访问权限*/

 

  5、Method类——获取方法

   封装方法的类是Method类,可以通过Class对象获取Method对象或对象数组,同样有4个方法。

  基于反射获取并执行方法的过程:

Method me=cls.getMethod("methodBame",null);
Object name=me.invoke(obj,null);

 

  6、反射处理数组

  数组与所有对象一样,都通过Class的对象描述,也可使用标准getClass()方法获得数组的Class对象。

  但是反射为普通类提供的构造函数访问不能用于数组,数组也没有可以访问的字段。

  反射处理数组使用java.lang.reflect.Array类提供的静态方法,可以创建新的数组,可以获得数组对象的长度,以及读、写数组对象的索引值。注意,java.util.Arrays包含实用的方法用于排序数组,并将他们转换为集合。

  反射机制创建数组:

/*第一个参数int.class指定数组类型,第二个参数声明数组中元素的个数。*/
int[] intArray=(int[]) Array.newInstance( int.class, 3);

/*访问通过反射创建的数组*/
/*intArray参数是一个具体的数组*/
Array.get (intArray,0);
Array.set (intArray,index,value); 

   思考,怎么重新调整现有数组大小?

  思路,使用反射创建相同类型的新数组,然后在返回新数组之前,将旧数组中所有数据复制到新创建的数组。

public Object growArray(Object array,int size){
        Class type=array.getClass().getComponentType();
        Object grown= Array.newInstance(type,size);
        System.arraycopy(array,0,grown,0,Math.min(Array.getLength(array),size));
        return grown;
    }

 

 

 

 

posted @ 2018-02-06 16:42  爆炸的果核  阅读(192)  评论(0编辑  收藏  举报