一、反射
1、概述
反射是允许在运行态动态生成Object对象,能够通过类Class信息获取属性、方法、注解,并能够动态调用,能够动态调用对象方法的机制。
2、获取Class对象
通过以下方式获取到Class对象:
- 通过对象的getClass()方法。
- 通过类的class成员变量。
- 通过Class类的forName()方法。
Student student = new Student();
//1. 通过对象的getClass()方法。
Class<? extends Student> clazz = student.getClass();
//2. 通过类的class成员变量。
Class<Student> clazz1 = Student.class;
//3. 通过Class类的forName()方法。
Class<?> clazz2 = Class.forName("reflect.reflect.Student");
3、创建对象
通过以下方式创建对象:
//调用方法:clazz.newInstance()
Student student1 = clazz.newInstance();
//获取构造器后调用方法:constructor.newInstance()
Constructor<? extends Student> constructor = clazz.getConstructor();
Student student2 = constructor.newInstance();
通过以下方式获取属性、方法和注解:
//获取属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
//获取方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
Class<?>[] types = method.getParameterTypes();
if (types != null && types.length > 0) {
System.out.println(types[0].getName());
}
}
//获取注解
Annotation[] annotations = clazz.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.annotationType().getSimpleName());
}
4、总结
反射的优点:
- 能够再运行态动态获取类的属性、方法和注解信息,能够动态生成对象。
反射的缺点:
- 破坏了类的封装性,通过反射能够读取private的属性、方法。
二、代理
代理是一种设计模式,作用是在不扩张目标对象的前提下,通过扩展代理类来对目标对象的功能进行增强。其模型为访问者通过代理对象来访问目标对象。一般包括代理对象、目标对象、目标对象接口三种角色。
1、静态代理
静态代理是在编译期就已经在代理类中确定了目标对象要扩展的功能,无法在运行态动态生成代理对象,灵活性不够。
代码实现 https://github.com/yangnk/JavaHelloworld/tree/master/src/main/java/reflect/proxy
2、动态代理
动态代理可以在运行态动态生成代理对象,适用于在运行态目标对象会灵活生成的。
(1)JDK原生动态代理
- 实现方法:原生的JDK动态代理重点是实现InvocationHandler接口,需要你重写invoke()方法,在这个方法里将需要增强的部分增强就好了。
- 实现原理:通过Proxy.newProxyInstance()方法创建实现InvocationHandler接口的invoke()方法,底层是通过反射来做到的。
(2)CgLib动态代理
- 实现方法:这个是第三方lib实现,需要引入cglib库,首先还是需要实现MethodInterceptor接口,重写其中的intercepter()方法,这个看起来和JDK 原生动态代理差不多。
(3)总结
JDK动态代理和CgLib动态代理区别:
- JDK Proxy在原生JDK中即可实现,通过实现InvocationHandler接口即可,他的原理是通过反射生成目标类的匿名类;而CgLib Proxy需要引入第三方包,他是通过asm来操作字节码,生成目标类的子类,在运行时将该子类的字节码加载进来。
- JDK proxy作为代理类,需要目标类有接口才能代理实现,即只能针对接口才能生成代理类;CgLib Proxy不需要目标类有接口就能代理实现。
参考文献
- Java三种代理模式:静态代理、动态代理和cglib代理:https://segmentfault.com/a/1190000011291179