Java 反射

获取 class 实例的三种方法

  • 通过 class 静态变量获取

    Class class = String.class;

  • 通过实例变量的 getClass() 获取

    String s = “kyle”;

    Class class = s.getClass();

  • 知道 class 的完整类名,通过静态方法 Class.forName() 获取

    Class class = Class.forName(“java.lang.String”);

通过反射创建实例

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

  • getName() 返回字段的名称

  • getType() 返回字段类型,例如 String.class

  • getModifiers() 返回字段的修饰符,是一个 int, 不同的 bit 表示不同的含义

 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

动态代理

静态代理:

  1. 定义接口
  2. 编写接口实现类
  3. interface i = new xxx(); xxx.m();

动态代码:

  1. 定义接口
  2. 通过 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)

  1. 使用的ClassLoader,通常就是接口类的ClassLoader
  2. 需要实现的接口数组,至少需要传入一个接口进去;
  3. 用来处理接口方法调用的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 });
    }
}