反射

缺点

  • 破坏封装:由于反射允许访问私有字段和私有方法,所以可能会破坏封装而导致安全问题。
  • 性能开销:由于反射涉及到动态解析,因此无法执行 Java 虚拟机优化

应用场景

  • 开发通用框架:像 Spring,为了保持通用性,通过配置文件来加载不同的对象,调用不同的方法。
  • 动态代理:在面向切面编程中,需要拦截特定的方法,就会选择动态代理的方式,而动态代理的底层技术就是反射。
  • 注解:注解本身只是起到一个标记符的作用,它需要利用发射机制,根据标记符去执行特定的行为。
class CSer {
    private String name;
    private int mvp;

    // get、set、构造器和toString
}
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {
    CSer niko = new CSer();
    niko.setName("niko");
    System.out.println(niko.getName());

    // 获取反射类的 Class 对象
    Class clazz = Class.forName("test.ReflectTest.CSer");
    // 通过 Class 对象获取构造方法 Constructor 对象
    Constructor constructor = clazz.getConstructor();
    // 通过 Constructor 对象初始化反射类对象
    Object o = constructor.newInstance();

    // 获取要调用的方法的 Method 对象
    Method setNameMethod = clazz.getMethod("setName", String.class);
    Method getNameMethod = clazz.getMethod("getName");
    // 通过 invoke() 方法执行
    setNameMethod.invoke(o, "glave");
    System.out.println(getNameMethod.invoke(o));
}

invoke源码

boolean override;

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
        InvocationTargetException {
    // 如果方法不允许被覆盖,进行权限检查
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            // 检查调用者是否具有访问权限
            checkAccess(caller, clazz, obj, modifiers);
        }
    }
    // 获取方法访问器(从 volatile 变量中读取)
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        // 如果访问器为空,尝试获取方法访问器
        ma = acquireMethodAccessor();
    }
    // 使用方法访问器调用方法,并返回结果
    return ma.invoke(obj, args);
}
  • MethodAccessor接口有三个实现类,其中的 MethodAccessorImpl 是一个抽象类,另外两个具体的实现类继承了这个抽象类

    • NativeMethodAccessorImpl:通过本地方法来实现反射调用;

    • DelegatingMethodAccessorImpl:通过委派模式来实现反射调用;

// MethodAccessor接口
public interface MethodAccessor {
    Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException;
}
private MethodAccessor acquireMethodAccessor() {
    // First check to see if one has been created yet, and take it
    // if so
    MethodAccessor tmp = null;
    if (root != null) tmp = root.getMethodAccessor();
    if (tmp != null) {
        // 先判断是否存在对应的 MethodAccessor 对象,如果存在那么就复用之前的 MethodAccessor 对象
        methodAccessor = tmp;
    } else {
        // Otherwise fabricate one and propagate it up to the root
        // 否则调用 ReflectionFactory 对象的 newMethodAccessor 方法生成一个 MethodAccessor 对象
        tmp = reflectionFactory.newMethodAccessor(this);
        setMethodAccessor(tmp);
    }

    return tmp;
}
public MethodAccessor newMethodAccessor(Method var1) {
    checkInitted();
    if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
        return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
    } else {
        // 先是生成了一个 NativeMethodAccessorImpl 对象
        NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
        // 再这个对象作为参数调用 DelegatingMethodAccessorImpl 类的构造方法
        // 使用了代理模式,将 NativeMethodAccessorImpl 对象交给 DelegatingMethodAccessorImpl 对象代理
        DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
        var2.setParent(var3);
        return var3;
    }
}
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
    private MethodAccessorImpl delegate;
	// 将 NativeMethodAccessorImpl 对象赋值给 DelegatingMethodAccessorImpl 类的 delegate 属性
    DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {
        this.setDelegate(var1);
    }

    // ReflectionFactory 类的 newMethodAccessor 方法最终返回 DelegatingMethodAccessorImpl 类对象。所以我们在前面的 ma.invoke() 里,其将会进入 DelegatingMethodAccessorImpl 类的 invoke 方法中。
    public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        // 这里调用了 delegate 属性的 invoke 方法,它又有两个实现类,分别是:DelegatingMethodAccessorImpl 和 NativeMethodAccessorImpl。按照我们前面说到的,这里的 delegate 其实是一个 NativeMethodAccessorImpl 对象,所以这里会进入 NativeMethodAccessorImpl 的 invoke 方法。
        return this.delegate.invoke(var1, var2);
    }

    void setDelegate(MethodAccessorImpl var1) {
        this.delegate = var1;
    }
}
class NativeMethodAccessorImpl extends MethodAccessorImpl {
    private final Method method;
    private DelegatingMethodAccessorImpl parent;
    private int numInvocations;

    NativeMethodAccessorImpl(Method var1) {
        this.method = var1;
    }

    public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        // 如果超过该阀值,那么就会生成另一个MethodAccessor 对象,并将原来 DelegatingMethodAccessorImpl 对象中的 delegate 属性指向最新的 MethodAccessor 对象
        if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
            MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
            this.parent.setDelegate(var3);
        }

        return invoke0(this.method, var1, var2);
    }

    void setParent(DelegatingMethodAccessorImpl var1) {
        this.parent = var1;
    }

    private static native Object invoke0(Method var0, Object var1, Object[] var2);
}
  • 第一次加载的时候使用的是 NativeMethodAccessorImpl 的实现,而当反射调用次数超过 15 次之后(可以通过 -Dsun.reflect.inflationThreshold 参数类调整),则使用 MethodAccessorGenerator 生成的 MethodAccessorImpl 对象去实现反射。

获取反射类的Class对象

  • Class.forName(),参数为反射类的完全限定名
Class c1 = Class.forName("test.ReflectTest.CSer");
// test.ReflectTest.CSer
System.out.println(c1.getCanonicalName());

Class c2 = Class.forName("[D");
// double[]
System.out.println(c2.getCanonicalName());

Class c3 = Class.forName("[[Ljava.lang.String;");
// java.lang.String[][]
System.out.println(c3.getCanonicalName());
  • 类名.class,只适合在编译前就知道操作的 Class
Class c1 = CSer.class;
// test.ReflectTest.CSer
System.out.println(c1.getCanonicalName());

Class c2 = String.class;
// java.lang.String
System.out.println(c2.getCanonicalName());

Class c3 = int[][][].class;
// int[][][]
System.out.println(c3.getCanonicalName());
  • .getClass()
CSer cSer = new CSer();
Class clazz = cSer.getClass();
// test.ReflectTest.CSer
System.out.println(clazz.getCanonicalName());

创建反射类的对象

  • 用 Class 对象的 newInstance() 方法
Class clazz = CSer.class;
CSer cSer = (CSer) clazz.newInstance();
  • 用 Constructor 对象的 newInstance() 方法
Class clazz = CSer.class;
Constructor constructor = clazz.getConstructor();
CSer cSer = (CSer) constructor.newInstance();

获取构造方法

  • getConstructor():返回反射类的特定 public 构造方法,可以传递参数,参数为构造方法参数对应 Class 对象;缺省的时候返回默认构造方法。
  • getDeclaredConstructor():返回反射类的特定构造方法,不限定于 public 的。
  • getConstructors():返回类的所有 public 构造方法。
  • getDeclaredConstructors():返回类的所有构造方法,不限定于 public 的。
Constructor<?>[] declaredConstructors = String.class.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
    System.out.println(declaredConstructor);
}

获取字段和方法

  • 同上,把关键字Constructor换成Field或Method
  • 在访问私有方法和字段时,我们需要调用 setAccessible(true) 方法来允许访问
posted @ 2024-07-14 17:24  n1ce2cv  阅读(12)  评论(0编辑  收藏  举报