虽然Java不是动态语言1,但Java语言具有一定的动态性,可以利用反射机制,字节码操作获得类似动态语言的特性,Java的动态性让编程更加灵活。
反射:指的是可以在程序运行时加载、探知、使用编译期间完全未知的类。加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,形象的称为反射。
反射机制的作用:重点在于动态性:动态加载类、动态获取类的信息(属性、方法、构造器);动态创建对象;动态调用方法、构造器;动态处理属性;此外还能处理泛型、注解。
获取Class对象:
Class.forName();(常用)
getClass();
.class;
代码:
- javaBean:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public class User {
private int id;
private int age;
private String name;
//javabean一定要有无参构造器
public User() {
}
public User(int id, int age, String name) {
super();
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
} - 获得User类的反射对象:
1
2
3
4
5
6
7String path = "com.sxt.test.bean.User";
Class clazz = Class.forName(path);//方法一
User u = new User();
Class clazz2 = u.getClass();//方法二
Class clazz3 = com.sxt.test.bean.User.class;//方法三 - 获得User类的属性:
1
Field f = clazz.getDeclaredField("name");
- 获得User类的方法:
1
2
3Method m01 = clazz.getDeclaredMethod("getName", null);
//如果方法有参数,则必须传递参数类型对应的Class对象
Method m02 = clazz.getDeclaredMethod("setName", String.class); - 获得User类指定的构造器:
1
Constructor constructor = clazz.getDeclaredConstructor(int.class,int.class,String.class);
- 通过反射API动态的操作:构造器,方法,属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//通过反射API调用构造方法,构造对象
User u1 = (User) clazz.getConstructor().newInstance();//调用了User的无参构造器
User u2 = (User)clazz.getConstructor(int.class,int.class,String.class).newInstance(1001,18,"席博");//调用了User带参构造器
//通过反射API调用普通方法 invoke(对象,参数)方法
User u3 = (User) clazz.getConstructor().newInstance();
Method method = clazz.getDeclaredMethod("setName", String.class);
method.invoke(u3, "aaa");//u3.setName("aaa");
//通过反射API操作属性
User u4 = (User) clazz.getConstructor().newInstance();
Field f = clazz.getDeclaredField("name");//通过反射获得属性
f.setAccessible(true); //这个属性不需要做安全检查,可以直接访问
f.set(u4, "bbb"); //通过反射直接写u4属性
f.get(u4);//通过反射读取u4属性 - 通过反射读取泛型的信息:ParameterizedType: 表示一种参数化的类型,比如Collection
; - 通过反射读取注解的信息,模拟处理注解信息的流程,具体参见:Java 注解
反射的性能问题:使用反射性能会降低(约30倍),setAccessible:启用和禁用访问安全检查的开关,设为 true 则表示反射的对象在使用时禁止 Java 语言访问检查。禁止安全检查,可以提高反射的运行速度(大约提高四倍)。
- 1.动态语言:程序运行时,可以改变程序结构或变量类型。常见的动态语言:Python、ruby、javascript ↩