类的加载概述
- 类的加载概述
- 程序要是用某个类时,类还没有加载进入内存(在硬盘),系统会通过加载、连接、初始化来实现对这个类的初始化。
- 加载:将class文件读入内存,并创建一个class对象。类一旦被使用就会创建一个唯一的class对象,它是一个可以操作方法区的数据结构的接口,并没有存储什么东西仅用作描述信息。
- 连接:
- 验证:是否有正确的内部结构,并和其他类协调一致。确保Class文件的字节流中包含的信息(方法区信息)符合当前虚拟机要求,并不会危害虚拟机自身的安全。如果有错误就会抛出异常
- 准备:负责为类的静态成员分配内存,并设置默认初始化值。这个时候进行内存分配的仅包括类信息(被static修饰的变量),而不包括实例变量(非静态成员变量),实例变量将会在对象实例化时随着对象一起分配在Java堆中。
- 解析:将类的二进制数据中的符号引用替换为直接引用
- 初始化:加载字节码、默认初始化、显示方法初始化、构造方法初始化
反射概述
- 反射概述(动态获取信息,动态调用对象的方法等)
- java反射机制是在运行中任何一个类都可知道它的属性和方法。
- 对于任意一个对象都可以调用它的属性和方法
- 想要解剖一个类需要获得字节码文件的class对象,再获得class类的方法。
- 三种方式获取字节码
- Class类中静态方法,class.forName()读取配置文件
Class clazz = Class.forName(“全包名”);//源文件阶段 - 静态属性 .class,锁对象
Class claszz = Dog.class;//字节码阶段 - object类getClass,比较文件是否是同一个字节码文件
Class clazz = dog.getClass();//创建对象阶段
都是同一字节码文件,即clazz是相同的
-
newInstance()方法
Dog dog = (Dog)clazz.newInstance();//通过空参创建对象
创建了一个狗对象,要注意newInstance()方法适用于无参构造函数创建对象,如果没有无参构造方法,需要使用Class的getConstructor() -
getConstructor()方法
如上图,会出现问题,这时候需要通过getConstrucor获取有参构造,再通过有参构造newInstance(…)创建对象。
-
反射获取属性
对于反射而言,一切都是透明的,要访问的属性即使是私有也可以获得,通过Field f= clazz.getDeclaredField()方法进行暴力反射获取,然后设定该属性可以访问f.setAccessible(true). -
反射获取方法
getMethod(“方法名”, 参数类型…)获取类中指定方法,invoke()调用该方法。
-
泛型
泛型只在编译期间有效,运行期间会被擦除,即,所有泛型类型在编译结束都会被擦除,java编译的字节码中没有泛型信息。如图,成功将字符串"abc"插入。
通过泛型写了一个设置属性的通用工具类:
-
动态代理概述(通过反射生成一个代理)
1.在java.lang.reflect包下提供了一个Proxy类和InvocationHandler接口,使用这个类和接口可以生成一个动态代理对象
2.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
调用InvocationHandler 的方法
InvocationHandler Object invoke(Object proxy, Method method, Object[] args)