缺点
- 破坏封装:由于反射允许访问私有字段和私有方法,所以可能会破坏封装而导致安全问题。
- 性能开销:由于反射涉及到动态解析,因此无法执行 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接口
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());
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)
方法来允许访问