类加载
Class类和Class对象
加载类完成后,堆内存的方法区产生Class类型的对象,Class类:描述类的类。
Class.forName
已知一个类的全类名,且该类在类路径下。Class<?> clazz = Class.forName("com.yanjing.reflection.User");
通过class属性获取
Class clazz = Person.class
调用实例的getClass()方法
Class clazz = person.getClass();
获取父类属性
Class clazz = son.getSuperclass();
基本内置类型的的包装类
Class clazz = Integer.TYPE;
各种类型的Class对象
类加载过程
类加载过程:加载——链接(验证、准备、解析)——初始化——使用——卸载
Object obj = new Object()发生了什么: 首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进jvm的内存中,你的类Object加载到方法区中,创建了Object类的class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。 作者:Goosy
链接:https://www.zhihu.com/question/24304289/answer/147529485
反射
动态语言VS静态语言
反射概念
Reflection(反射)允许程序在运行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
API
- getName
- getSimpleName
- getFields
- getDeclareFields
- getMethods
- getDeclareMethods
- getMethod
- getDeclaredConstructor
- getDeclaredConstructors
-
newInstance
aClass.getDeclaredConstructor().newInstance()
aClass.getDeclaredConstructor(Class<?>... parameterType).newInstance(Object ... initargs)
getDeclareMethod+invoke (setAccessible)
aClass.getDeclareMethod(String name, Class<?>...parameterTypes);
// method.setAccessible(true);
method.invoke(Object obj, Object[] args)
field.get/set (setAccessible)
this.getClass().getDeclaredField(String name);
// filed.setAccessible(true);
field.get(this);
field.set(this, 'abc')
获取泛型信息
获取注解信息
getAnnotation
-
应用
对所有成员变量进行处理(判断)。
private boolean hasValue() {
Field[] fields = this.getClass().getDeclaredFields();
return Arrays.stream(fields).anyMatch(field -> {
field.setAccessible(true);
try {
return Objects.nonNull(field.get(this));
} catch (IllegalAccessException ignore) {
return false;
}
});
}
注:反射调用方式比普通方式慢几十倍,setAccessible可提高一些速度
点击查看【bilibili】动态代理
[ ] Java 动态代理作用是什么?
代理
- 减少代理类数量(
- 一个动态代理 , 一般代理某一类业务
- 一个动态代理可以代理多个类,只要这些类实现的是同一接口
- 修改接口中的方法不会影响实现类
两种实现
JDK动态代理
使用java反射包中的类和接口实现动态代理的功能。
反射包java.lang.reflect
类**InvocationHandler**
,**Method**
,**Proxy**
CGLIB动态代理(了解)
glib是第三方的工具库,创建代理对象
- cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法,实现功能的修改。
- 因为cglib是继承,重写方法,所以要求目标类不能是fina1的,方法也不能是final的。cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,比如mybatis,spring框架中都有使用。
实现过程
步骤和demo
- 创建接口,定义目标类要完成的功能
- 创建目标类实现接口
- 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
- 调用目标方法
- 增强功能
使用Proxy类的静态方法,创建代理对象,并把返回值转换成接口类型,然后通过代理执行方法。 ```java /**
- InvocationHandler is the interface implemented by the invocation handler of a
- proxy instance.Each proxy instance has an associated invocation handler.
- When a method is invoked(float price = proxy.sell(1)) on a proxy instance,
- the method invocation is encoded and dispatched to the invoke method of its
invocation handler. */ public class MySellHandler implements InvocationHandler {
private final Object target;
// 传入是谁的对象,就给谁创建代理 public MySellHandler(Object target) {
this.target = target; }
/**
- 参数都是jdk直接传入
- @param proxy 来自newProxyInstance创建的
- @param method 来自proxy.method调用时的method
- @param args 来自proxy.method调用时传入的参数
- @return
@throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用目标方法 method.invoke(target, args);
// 增强功能 // … } }
public class MainShop {
public static void main(String[] args) {
// 1. 创建目标对象
UsbSell factory = new UsbKingFactory();
// 2. 创建InvocationHandler对象
InvocationHandler handler = new MySellHandler(factory);
// 3. 创建代理对象
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
handler);
// 4. 通过代理执行方法
float price = proxy.sell(1);
}
}
总结
- 为什么动态?是在运行期间创建代理对象。目标对象是活动的,根据需求实现一个具有增强功能的InvocationHandler,传入是谁的对象,就给谁创建代理。
- 代理对象通过
Proxy.newProxyInstance
创建,需要用到类加载器(任意一个类对象的getClassLoader()获取)和接口(target.getClass().getInterfaces())),这个前提就是要用到JDK反射(invoke方法内的method.invoke也用到反射),以及目标对象和代理对象都实现同一个接口。 - 运行期怎么动态代理可以通过debug方式
- 动态代理的是接口,注意类型要用接口,这样才是代理的实例,如果类型直接用实现,就是目标实例