对象创建的一般流程

在讲反射之前,先描述一下在一般情况下,一个类的对象是如何创建的。如运行:

Mobile m = new Mobile();

根据类的加载流程我们知道:

  1. 当JVM之前未加载过Mobile类,则进入类加载过程
  2. 类加载器从磁盘上找到Mobile.class字节码文件
  3. 类加载器将字节码文件加载进虚拟机内存,同时在堆中产生一个Class类的对象
  4. 类加载完成后,该类的对象所需的内存空间已经完全确定了(编译完成后则确定了),因此此时为新生对象在堆中开辟内存空间。
  5. 对分配到内存空间的数据类型初始化为零值。
  6. 对对象头进行设置,如所属类(这个对象是哪个类的实例)、对象哈希码等
  7. 调用对象的init()方法,根据传入值为对象的属性赋值
  8. 在线程的虚拟机栈中新建对象引用,指向刚刚在堆中建立的对象。
    下图展示从类加载到为新生对象分配内存的流程:
    图片说明

    反射原理

    在new对象的一般流程的基础上,反射就是:通过某个类的全类名(字符串),加载该类的字节码到虚拟机内存中,获得该类的Class对象,在获得了运行时类对象后,可以根据这个运行时对象直接取得类的所有属性和方法。流程如下所示:
    图片说明

    使用反射

    获取Class对象

    要调用一个类的方法或属性,以及关于该类其他的信息,就是通过反射产生的Class对象提供的接口实现的。要通过反射获得某类的Class对象,可以:

    使用全类名和Class.forName方法,反射大多使用这种方式

    Class clz = Class.forName("java.lang.String");

    使用.class方法,当编译前就知道要操作的类的时候才可以使用

    Class clz = String.class;

    使用一个类的对象的getClass()方法

    String str = new String("Hello");
    Class clz = str.getClass();

    通过反射创建类对象

    通过Class对象的newInstance()方法

    Class clz = Mobile.class;
    Mobile m = (Mobile)clz.newInstance();
    这种方式只能使用Mobile类的默认的无参构造方法。

    获得了类的构造器对象后,用构造器对象获得类的对象

    Class clz = Mobile.class;
    Constructor constructor = clz.getConstructor();
    Mobile m = (Mobile)constructor.newInstance();
    这种方式就可以根据需要选择不同的构造器进行构造对象了,获得不同的构造器的方式是在getConstructor()方法中写入希望获得的构造器的传入参数类型,如:
    Constructor constructor = clz.getConstructor(String.class, int.class);

    获得类的属性

    getFields()方法

    获得类的私有属性外的所有属性的数组:
    Class clz = Mobile.class;
    Field[] fields = clz.getFields();
    for (Field field : fields) {
    System.out.println(“属性名是:”+field.getName());
    }

    getDeclaredFields()方法

    和getFields()方法类似,而此方法可以获得类的所有属性

    getField(String fieldName)方法

    根据变量名获得单个的公有的属性

    getDeclaredField(String fieldName)方法

    根据变量名获得单个的公有或私有的属性

    获得类的方法

    getMethods()方法

    获得类所有的公有方法的对象数组

    getDeclaredMethods()方法:

    获得类的所有方法的对象数组

    getMethod(String name, Class<?> ... parameterTypes)方法

    根据方法名和方法形参的Class对象获得类的一个公有方法

    getDelcaredMethod(String name, Class<?> ... parameterTypes)方法

    根据方法名和方法形参的Class对象获得类的一个公有或私有方法

    调用获得的方法对象:invoke(Object obj,Object... args)

    obj:要调用本方法的对象
    args:调用方法时传入的实参
    例:
    Method method = clz.getMethod("show", String.class);  
    //实例化一个Student对象  
    Object obj = clz.getConstructor().newInstance();  
    m.invoke(obj, "iPhone");