Java的反射机制是非常强大的,反射出现之前Java只是一门静态语言,当JDK5诞生发布了注解、反射的功能之后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 + "}";
}
}
- 通过newInstance方法实例化对象,只会调用类的无参构造方法进行实例化对象。如果类中没有无参构造方法强行进行构造会爆出异常
@Test
public void test1() throws Exception {
User s1 = (User)Class.forName("reflection.third.User").newInstance(); //只会调用无参构造器进行实例化
System.out.println(s1);
}
- 通过反射加载类的构造方法然后进行构造。
@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());
}
建议使用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); //传入空对象即可
}
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));
}
4. 总结
- newInstance方法实例化对象只会调用无参构造函数,如果没有无参构造函数将会报出异常。
- 使用反射获取一些信息时如果权限不够,可以使用setAccessible(true)来临时提升权限
- 反射调用静态方法时,invoke方法可以不传入实例化对象传入null即可。
- 反射调用静态变量时,set()、get()方法一样不需要传入实例化对象,直接传入null;