Java的反射机制是非常强大的,反射出现之前Java只是一门静态语言,当JDK5诞生发布了注解、反射的功能之后Java的功能越发变得强大,成为了一门准动态语言弥补了Java强类型语言的不足。

通过Java的反射机制可以动态的获取到非常多的信息(如图)

java 动态给对象增加注解对象 java动态创建对象_实例化

1. 动态创建对象

package reflection.third;

public class User {
    private String name ;
    private int age;
    private static int value = 100;
    public User(){      //无参构造

    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private static void print(){			//public的方法就不需要反射获取了
        System.out.println("value = " + value);
    }

    @Override
    public String toString() {
         return "User{" + "name=" + name  + ", age=" + age + "}";
    }
}
  1. 通过newInstance方法实例化对象,只会调用类的无参构造方法进行实例化对象。如果类中没有无参构造方法强行进行构造会爆出异常
@Test
public void test1() throws Exception {
    User s1 = (User)Class.forName("reflection.third.User").newInstance();           //只会调用无参构造器进行实例化
    System.out.println(s1);
}

java 动态给对象增加注解对象 java动态创建对象_实例化_02

  1. 通过反射加载类的构造方法然后进行构造。
@Test
public void test2() throws Exception {
     //1. 空构造
     Constructor c1 = Class.forName("reflection.third.User").getDeclaredConstructor();
     User s1 = (User)c1.newInstance();
     System.out.println(s1);

     //2. 通过参数类型、顺序指定获取构造方法。
     Constructor c2 = Class.forName("reflection.third.User").getDeclaredConstructor(String.class,int.class);
     User s2 = (User)c2.newInstance("姓名", 1);         //注意参数类型顺序匹配
     System.out.println(s2.toString());
 }

java 动态给对象增加注解对象 java动态创建对象_User_03

建议使用Constructor构造。构造方法和Field字段、Method方法一样有四种类型。



2. 操作普通方法和静态方法

使用invoke(Object o,Object …args)执行方法,由于普通方法是实力化对象分配的方法,所以执行时需要指定是哪个实例化对象操作;而静态方法则不需要,因为静态方法不属于任何一个实例化对象。
如果修饰符是private可以调用setAccessible(true)临时的将权限提升到public进行访问。

@Test
public void test3() throws Exception{
    //1. 获取普通方法
    User user = (User)Class.forName("reflection.third.User").newInstance();
    Method setName = Class.forName("reflection.third.User").getDeclaredMethod("setName", String.class);
    setName.invoke(user,"你好");
    System.out.println(user.toString());

    //2. 获取静态方法
    Method print = Class.forName("reflection.third.User").getDeclaredMethod("print");
    print.setAccessible(true);
    print.invoke(null);			//传入空对象即可
}

java 动态给对象增加注解对象 java动态创建对象_实例化_04


3. 操作普通变量和静态变量

获取到的字段可以调用set(Object obj,Object …args)设置属性的值,调用get(Object obj)方法获取属性的值

@Test
public void test4() throws Exception{
    //1. 获取普通变量
    User user = (User)Class.forName("reflection.third.User").newInstance();
    Field name1 = Class.forName("reflection.third.User").getDeclaredField("name");
    name1.setAccessible(true);
    name1.set(user,"姓名");
    System.out.println(name1.get(user));

    //2. 获取静态变量
    Field name2 = Class.forName("reflection.third.User").getDeclaredField("value");
    name2.setAccessible(true);
    name2.set(null,9999);
    System.out.println(name2.get(null));
}

java 动态给对象增加注解对象 java动态创建对象_实例化_05


4. 总结

  1. newInstance方法实例化对象只会调用无参构造函数,如果没有无参构造函数将会报出异常。
  2. 使用反射获取一些信息时如果权限不够,可以使用setAccessible(true)来临时提升权限
  3. 反射调用静态方法时,invoke方法可以不传入实例化对象传入null即可。
  4. 反射调用静态变量时,set()、get()方法一样不需要传入实例化对象,直接传入null;