类加载
1.类加载
在Java代码中, 类型 在加载、连接和初始化过程 都是在程序运行期间完成的。
-
类型: 这里指的是Class类,比如有一个User对象,而这里的类型指的是User.class,而不是 new出来的User对象。
-
加载: 将指定class文件,或远程url文件获取,然后加载到内存中
-
连接: 确定类与类之间的引用关系,验证和检验class文件的准确性。这里分为三个阶段
-
初始化: 对加载的类中的静态变量赋值正确的初始化值的过程
-
程序运行期间: 意思是加载、连接、初始化过程都是在Runtime运行时完成的,不是静态编译时完成的。
1.1 类加载--连接过程又分为三个阶段
-
验证: 验证class文件的正确性,虽然大多数的class文件都是通过javac编译而来,但是编译后的class文件是可以再次被文本编辑器手动修改的。
-
准备: 为类型中的静态变量分配内存,并初始化赋值默认值
注意举例:public static int a = 1; 针对该变量a,在该阶段,会为a分配内存,且初始化默认值。
这里不会解析到 a =1,这里只会根据数据类型来决定默认值,即int--0,double--0.0,boolean--false,object--null,等,至于执行 a = 1 的操作,是在后续的初始化阶段完成。 -
解析: 将类中的符号引用转换成直接引用
1.2 类加载的几种途径
类加载指class文件的二进制数据加载到内存中,将其放入到方法区中,并且分配内存,创建一个 java.lang.Class 对象(jvm规范并没有要求Class对象放在哪里,HotSpot将其放入到方法区内),用来封装类在方法区的数据结构,这就是不管该类有多少个实例对象,都只会有一个Class对象的原因。
类加载的途径:
- 本地的class文件,例如classpath下的class文件
- 通过网络下载class文件
- 从zip,jar包等归档文件中提取class文件
- 从专有的数据库中加载class文件
- 将源文件编译成class文件,例如动态代理,和aop切面
1.3 总结点
- 对于静态变量来说,只有直接定义了静态变量字段的类,才会被初始化
- 在一个类初始化的时候,必须是其父类先被初始化完毕
2.类加载器
jvm加载class文件,解析class参数到内存中,这过程依赖类加载器来实现。
3.导致jvm虚拟机生命周期结束的四种原因
- 手动调用System.exit()
- 程序正常执行结束
- 程序遇到异常,导致程序终止
- 操作系统异常,导致jvm停止
4.类的主动使用和被动使用
java类或接口只要在首次主动使用的情况才会初始化他们
4.1 主动使用的七种场景
- 实例化对象
- 调用类的静态变量,设置静态变量赋值
- 调用类的静态方法
- 使用反射处理类,例如使用Class.forName来实例化对象
- 针对继承父子关系时,实例化子类的同时,必然会主动使用其父类
- 被jvm虚拟机认定为启动类的类,例如执行当前main的类
- 针对jdk1.7之后,支持动态语言调用处理的结果对应的类没有初始化的,则初始化
4.2 被动使用
不是主动使用的都为被动使用,被动使用的特点是都不会导致类的初始化。