在不少状况下,咱们知道如何编写反射相关类或者方法,可是没法口述反射是什么,里面的机制是什么,下面我先如浅入深介绍反射。设计模式
反射 (Reflection) 是 Java 的特征之一,它容许运行中动态加载Java 程序获取自身的信息,而且能够操做类或对象的内部属性,是一种功能强大且复杂的机制,能够用在下面四个方面:数组
上面是正式的反射定义,比较抽象,用个大白话来讲,反射就是动态加载类、调用方法和访问属性,它不须要事先知道运行对象是谁。反射的重点在运行时而不是编译时,也就是动态加载。下面咱们先来看下一个简单的例子bash
// 普通new
User user = new User();
user.setEmail("xxxx@xxx.com");
// 反射例子
try {
Class clz = Class.forName("com.fomin.demo.model.User");
Method method = clz.getMethod("setEmail", String.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, "aaa@xx.com");
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
| InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
复制代码
上面须要一个User实例,正常状况下,咱们只须要new一个实例就行,但咱们也会遇到一些特殊状况,我不知道初始化的类对象是什么,没法使用new进行实例化,这就须要在动态运行时才须要建立一个实例。框架
Java的反射机制的实现要借助于4个类:Class,Constructor,Field,Method,而且若是须要建立实例,可使用newInstance建立,例如,clz.newInstance或者constructor.newInstance
复制代码
//使用 Class.forName 静态方法
Class clz = Class.forName("com.fomin.demo.model.User");
//使用 .class 方法
Class clz = User.class;
//使用类对象的 getClass() 方法
User user = new User();
Class clz = user.getClass();
复制代码
//获取指定参数得到public构造函数
Constructor<T> getConstructor(Class<?>... parameterTypes);
//根据指定参数获取public和非public的构造函数
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);
复制代码
//获取类的全部声明字段,但不能获得其父类的成员变量,包含私有的
Field[] getDeclaredFields()
//获取指定参数的类的全部声明字段,但不能获得其父类的成员变量,包含私有的
Field getDeclaredField(String name)
//获取类的全部公有声明字段,但不能获得其父类的成员变量
Field[] getFields()
//获取指定参数的类的全部公有声明字段,但不能获得其父类的成员变量
Field getField(String name)
复制代码
//获取类的全部公用(public)方法,包括其继承类的公用方法
Method[] getMethods()
//获取特定的公用(public)方法,第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
Method getMethod(String name, Class<?>... parameterTypes)
//获取类或接口声明的全部方法,包括公共、保护、默认访问和私有方法,不包括继承方法
Method[] getDeclaredMethods()
//获取特定的方法,第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
复制代码
属于Method的一个方法,用来反射执行方法的,包含两个参数,一个是Object obj表示被调用方法底层所属对象,Object... args表示调用方法是传递的实际参数。 invoke中核心在MethodAccessorImpl,NativeMethodAccessorImpl,DelegatingMethodAccessorImpl这三个类中,其中NativeMethodAccessorImpl和DelegatingMethodAccessorImpl继承了抽象类MethodAccessorImpl。而且 NativeMethodAccessorImpl 对象交给 DelegatingMethodAccessorImpl 对象代理。 在执行invoke时,首先须要对非重写方法检查权限,对非public方法,进行二次检查checkAccess。ide
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
复制代码
获取当前的MethodAccessor,若是是空的,调用acquireMethodAccessor建立,首先先从root获取,仍是为空调用ReflectionFactory.newMethodAccessor建立一个,并设置在root中。模块化
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}
复制代码
最后调用NativeMethodAccessorImpl中的native方法invoke0函数
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
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);
复制代码
反射使用的地方不少,例如AOP思想就是须要用到发射、模块化的开发,经过反射去调用对应的字节码;动态代理设计模式也采用了反射机制, Spring/Hibernate 等框架。 优势:性能
缺点:ui