版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
1.类加载机制
JVM把class文件加载到内存,并对数据校验,解析和初始化,最终形成JVM可以直接使用的java类型的过程
1.1加载
将class文件字节码加载到内存,并将这些静态数据转化成方法区中运行时的二进制的数据结构,在堆中生成一个代表类的java.Lang.Class,作为方法区类数据的访问入口
1.2链接
将java的二进制代码合并到jvm的运行状态之中的过程
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题。
- 准备:正式为变量(static变呈)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配
- 解析:虚拟机常量池内的符号弓用替换为直接引用的过程
1.3初始化
- 初始化阶段是执行类构造器clinit()方法的过程。类构适器clinit()是由编译器自动收集
类中的所有类变量的赋值动作和静态语句块(static块)中的语法合并产生的· - 当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先对其父类初始化
- 虚拟机会保证一个类的cilnit()方法在多线程环境中被正确加锁和同步
发生类的初始化:类的主动引用
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 运行main方法所在的类
- 当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先对其父类初始化
不会发生类的初始化:类的被动引用
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。通过子类引用父的静态变量不导致子初始化
- 沮叟类引用,不会岌此类的初始化
- 引用此类常量不会触发此类的初始化(常量在编译阶段就存入调用类的常量池中了)
2.深入类加载器
2.1.类加载器的层次结构
-
引导类加载器:
加载java核心库
不继承java.lang.classLoader
加载扩展类加载器和应用程序类加载器
原生代码实现 -
扩展类加载器:
加载java扩展库
加载应用程序类加载器
继承java.lang.classLoader -
应用程序类加载器:
根据java应用的类路径加载java应用的类
继承java.lang.classLoader -
自定义类加载器:
2.2.类加载器的代理模式
-
代理模式, 交给其他类加载器加载
-
.双亲委托机制,某个类加载器接到加载类的请求时,优先交给父类加载器加载。保证java核心类库的安全,并不是所有加载 器都是双亲委托机制
同一个类被不同的加载器加载,JVM也认为是不同的类