• 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;
        }

     

  • 相关阅读:
    AJAX 验证用户名是否存在
    字符串变量中保存路径
    hdu Kaitou Kid The Phantom Thief (2)
    hdu 连连看
    hdu Sequence one
    hdu Sticks
    hdu Nightmare
    hdu Sudoku Killer
    hdu Dota all stars
    hdu Remainder
  • 原文地址:https://www.cnblogs.com/bigbigbigo/p/8423035.html
Copyright © 2020-2023  润新知