1.反射概念
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
根据类的全限定名可以从JVM的方法区(类加载后存放在方法区中)获取类所有的信息(名称, 常量,属性,静态代码块,构造器,方法,接口,权限)
一个类的构成:名称, 常量,属性,静态代码块,构造器,方法,接口,权限,所以反射能够操作的东西也无非是这些内容
2.使用反射的方式
1.Class clazz = object.getClass //通过实例的getClass()方法获取类信息
2.Class clazz = Object.class //直接获取
3.Class clazz = Class.forName("com.mysql.jdbc.Driver");//类加载器
本质调用public final native Class<?> getClass();直接调用本地方法去拿相关信息
3.世人都说反射慢
由于反射获取属性,方法,类加载等操作都是调用native接口和底层交互,所以导致了操作慢
但是JDK 其实对反射做了优化
1.优化一引入ReflectionData类,缓存类,对于读取Fields,Methods之类的操作方法返回的数据做了一次缓存,除了第一次读取,其他都是内存数据比较快
private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) {
checkInitted();
Field[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
//有缓存则返回
res = rd.publicFields;
if (res != null) return res;
}
// No cached value available; compute value recursively.
// Traverse in correct order for getField().
List<Field> fields = new ArrayList<>();
if (traversedInterfaces == null) {
traversedInterfaces = new HashSet<>();
}
// Local fields
//没有则调本地方法获取
Field[] tmp = privateGetDeclaredFields(true);
addAll(fields, tmp);
// Direct superinterfaces, recursively
for (Class<?> c : getInterfaces()) {
if (!traversedInterfaces.contains(c)) {
traversedInterfaces.add(c);
addAll(fields, c.privateGetPublicFields(traversedInterfaces));
}
}
// Direct superclass, recursively
if (!isInterface()) {
Class<?> c = getSuperclass();
if (c != null) {
addAll(fields, c.privateGetPublicFields(traversedInterfaces));
}
}
res = new Field[fields.size()];
fields.toArray(res);
//加入缓存
if (rd != null) {
rd.publicFields = res;
}
return res;
}
2.优化二 对于Field,Method,Constructor的访问加入了代理类,在调用invoke(),或new Instance()等方法时当次数>15次时,创建代理类实现
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);
}
1.动态代理概念
代理:为其他对象提供一种代理以控制对这个对象的访问
动态代理:程序运行过程中动态创建代理类
2.动态代理实现的两种方式
1). Java反射方式:实现java.lang.reflect.InvocationHandler接口,且实现invoke()方法
2). cglib方式:实现CGLIB提供的org.springframework.cglib.proxy.MethodInterceptor,且实现intercept()
举例:鹿晗是明星,找他工作先要找经纪人
/**
* @author z
* @date 2020-10-13 16:04
**/
public class LuHan implements Star {
@Override
public void work() {
System.out.println("鹿晗工作");
}
}
Java反射方式案例:
public class ManagerProxy implements InvocationHandler {
private Star star;
//经纪人不一定只管一个人
public ManagerProxy(Star star) {
this.star = star;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("经过经纪人");
Object o = method.invoke(star, args);
return o;
}
public static void main(String[] args) {
Star luhan = new LuHan();
ManagerProxy proxy = new ManagerProxy(luhan);
Star star = (Star) Proxy.newProxyInstance(
luhan.getClass().getClassLoader(),
luhan.getClass().getInterfaces(),
proxy);
star.work();
}
}
Cglib方式案例:
public class ManagerCglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("经过经纪人");
Object o = methodProxy.invokeSuper(object, args);
return o;
}
public static void main(String[] args) {
ManagerCglibProxy cglibProxy = new ManagerCglibProxy();
//cglib方式简洁很多,但是Enhancer不能代理final类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(LuHan.class);
enhancer.setCallback(cglibProxy);
Star star = (Star) enhancer.create();
star.work();
}
}
两次输出:
经过经纪人
鹿晗工作
cglib效率会比java反射方式高,但是cglib方式不能代理finl类