Java 反射
获取 class 实例的三种方法
通过反射创建实例
1
2
3
4
|
// 获取实例
Class class = String.class;
// 创建实例, 只能调用 `public` 的无参构造方法,带参数的构造方法,或者非 public 的构造方法都无法通过 Class.newInstance() 调用。
String s = (String) class.newInstance();
|
获取字段方法
-
Field getField(name)
根据字段名称获取某个public 的 field,包括父类
-
Field getDeclaredField(name)
根据字段名称获取当前类的某个 field,不包括父类
-
Field[] getFields()
获取所有 public 的field,包括父类
-
Field[] getDeclaredFields()
获取所有field,不包括父类
Field
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public final class String {
private final byte[] value;
}
Field f = String.class.getDeclaredField("value");
f.getName(); // "value"
f.getType(); // class [B 表示byte[]类型
int m = f.getModifiers();
Modifier.isFinal(m); // true
Modifier.isPublic(m); // false
Modifier.isProtected(m); // false
Modifier.isPrivate(m); // true
Modifier.isStatic(m); // false
|
获取字段值
1
2
3
4
5
6
7
|
Person p = new Person("kyle");
Class class = p.getClass();
Field f = class.getDeclaredField("name");
// 不管这个字段是不是 public ,都运行访问
f.setAccessible(true);
Object value = f.get(p);
System.out.println(value); // "kyle"
|
设置字段值
1
2
3
|
// 不管这个字段是不是 public ,都运行访问
f.setAccessible(true);
f.set(p, "zhao");
|
获取方法
- Method getMethod(name, Class…) 获取某个 public 的 method, 包括父类
- Method getDeclaredMethod(name, Class…) 获取当前类的某个 method,不包括父类
- Method getMethods() 获取所有 public 的 method,包括父类
- Method getDeclaredMethods() 获取当前类的所有 method,不包括父类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Student extends Person {
public int getScore(String type) {
return 99;
}
private int getGrade(int year) {
return 1;
}
}
class Person {
public String getName() {
return "Person";
}
}
Class s = Student.class;
s.getMethod("getScore", String.class);
// 获取 private 的方法 getGrade
s.getDeclaredMethod("getGrade", int.class);
|
Method
- getName() 返回方法名称
- getReturnType() 返回方法返回值类型,也是class 实例,例如: String.class
- getParameterTypes() 返回方法的参数类型,是 class 数组,[String.class, int.class]
- getModifiers() 返回方法的修饰符
调用方法
1
2
3
4
5
6
7
8
9
10
11
|
String s = "kyle zhao";
// 获取 String substring 方法,参数为 int
Method m = String.class.getMethod("substring", int.class);
// 为了调用非public方法, 通过Method.setAccessible(true)允许其调用
// m.setAccessible(true);
// 在 s 对象上调用该方法并获取结果, kyle
String r = (String) m.invoke(s, 4);
// 如果获取到的是静态方法,第一个对象参数为 null
// Integer.parseInt(String);
// m.invoke(null, "12345");
|
调用构造方法
Constructor
当前类定义的构造方法,和父类无关
- getConstructor(Class…)
- getDeclaredConstructor(Class…)
- getConstructors()
- getDeclaredConstructors()
1
2
3
4
|
// 获取构造方法Integer(int):
Constructor cons1 = Integer.class.getConstructor(int.class);
// 调用构造方法:
Integer n1 = (Integer) cons1.newInstance(123);
|
获取继承关系
1
2
3
4
5
6
7
8
|
Class i = Integer.class;
// 获取父类
Class n = i.getSuperclass(); // Number
// 获取实现的接口
class[] is = i.getInterfaces();
// 判断一个向上转型是否可以实现
Number.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Number
Integer.class.isAssignableFrom(Number.class); // false,因为Number不能赋值给Integer
|
动态代理
静态代理:
- 定义接口
- 编写接口实现类
- interface i = new xxx(); xxx.m();
动态代码:
- 定义接口
- 通过 JDK 提供的 Proxy.newProxyInstance() 创建 接口对象
这种在运行期动态创建了一个接口对象的方式称为动态代码,JDK 提供的动态创建接口对象的方式,就叫动态代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
InvocationHandler handler = (proxy, method, args1) -> {
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args1[0]);
}
return null;
};
Hello hello = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), new Class[]{Hello.class}, handler);
hello.morning("Kyle");
}
}
interface Hello {
void morning(String name);
}
|
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- 使用的
ClassLoader
,通常就是接口类的ClassLoader
;
- 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler
实例。
把上面的动态代理改写为静态实现类大概长这样:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class HelloDynamicProxy implements Hello {
InvocationHandler handler;
public HelloDynamicProxy(InvocationHandler handler) {
this.handler = handler;
}
public void morning(String name) {
handler.invoke(
this,
Hello.class.getMethod("morning", String.class),
new Object[] { name });
}
}
|