爱转圈笔记
勤思、体悟、总结、分享
类加载&反射
ClassLoader
类的加载
当程序要使用某个类时,如果该类未加载到内存中,则系统会通过加载、连接、初始化三个步骤来对该类进行初始化加载。
通过类加载器将类的class文件读入内存并创建一个java.lang.Class对象。
类的连接
- 当类被加载后,系统为之生成一个Class对象,然后会进入连接阶段,将类的二进制数据合并到JRE中。
- 类连接的三个阶段:
- 验证:检验被加载的类是否有正确的内部结构,并和其他类不冲突。
- 准备:为类的类变量分配内存,并设置默认初始值。
- 解析:将类的二进制数据中的符号引用替换成直接引用。
类的初始化
- 虚拟机负责对类进行初始化,主要就是对类变量指定初始值。
- 指定初始值的两种方式:
- 声明类变量时指定初始值;
- 使用静态代码块指定初始值。
- 类初始化的时机(何时初始化):
- 创建类的实例;
- 调用某个类的静态方法;
- 访问某个类或接口的类变量。
- 使用反射方式强制创建某个类或接口的Class对象。
- 初始化某个类的子类。
- 使用java.exe命令运行某个类。
- 类不初始化的情况:
- 当某个类的静态变量使用final修饰时,并且它的值在编译时就可以确定下来(相当于使用了常量,所以不会初始化类)。
- 使用ClassLoader中的loadClass()方法,只会加载,不会初始化。
类加载器
类加载器负责将.class文件加载到内存中并创建一个java.lang.Class对象。
- 当JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构。
- Bootstrap ClassLoader:根类加载器。
- 负责加载Java的核心类。
- Extension ClassLoader:扩展类加载器。
- 负责加载JRE扩展目录中的Jar包。
- System ClassLoader:系统类加载器。
- 负责加载JVM启动时来自Java命令的类。
- Bootstrap ClassLoader:根类加载器。
类加载机制
- 全盘负责:当一个类加载器负责加载某个类时,该类所以来的和引用的其他类也将由该类加载器负责加载,除非显示使用另一个类加载器来加载。
- 父类委托:先让父类加载器试图加载该类,在无法加载时再尝试从自己的类路径加载该类。
- 缓存加载:当程序要使用某个类时,类加载器先从缓存区中搜索该类,只有当缓存区不存在该类对象时,系统才会将该类载入缓冲区中(这也是为什么修改类后要重启JVM才生效的原因)。
注意:类加载器之间的层次关系并不是类继承中的父子关系,这里指的是类加载器实例之间的关系。
根类加载器(层次最高) <-- 扩展类加载器 <–系统类加载器 <–自定义加载器。
URLClassLoader类
- Java为ClassLoader提供了一个实现类URLClassLoader,系统类加载器和扩展类加载器都继承了此类。
- URLClassLoader可以从本地文件系统获取二进制文件来加载类,也可以从远程服务器获取二进制文件来加载类。
反射
什么是反射机制
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
通过反射获取Class对象信息
- JAVA程序中获得Class对象的三种方式:
- 使用Class类的forName(String ClazzName)静态方法。
- 使用某个类的class属性,如User.class。
- 调用某个对象的getClass()方法。
- 从Class对象中获取信息
- 通过Class对象可以得到很多Constructor/Method/Field等对象,通过这些对象可以调用方法、创建实例等(具体的方法自行查阅)。
动态代理(AOP原理)
通过反射生成动态代理
在Java的java.lang.reflect包下提供了一个Proxy类和InvocationHandler接口,通过使用这个类和接口可以生成动态代理类或动态代理对象(具体方法自行查阅)