jvm之类加载机制

文章目录

    • 类加载的过程
      • 1. 加载
      • 2. 验证
      • 3. 准备
      • 4. 解析
      • 5. 初始化
    • 类加载器
    • 类加载机制:
      • 双亲委托的好处
    • 相关问题
      • 1. [new 一个对象背后发生了什么](https://zhuanlan.zhihu.com/p/101031254)
      • 2. 下面这段代码能运行吗?为什么
      • 3. [能不能自定义一个类叫java.lang.System](https://zhuanlan.zhihu.com/p/68089617)

jvm将类的数据从class文件加载到内存中、形成可以被jvm直接使用的Class对象的过程成为类加载机制。

类的生命周期中的加载、验证、准备、解析、初始化属于类加载机制。
jvm之类加载机制_第1张图片

类加载的过程

1. 加载

通过类的全限定名获取二进制字节流、字节流转为方法区的运行时数据结构、在内存中生成代表这个类的java.lang.Class对象

2. 验证

确保Class文件的字节流包含的信息符合jvm的要求

3. 准备

为类中的静态变量分配内存并设置初始值

4. 解析

将常量池中的符号引用替换为直接引用

5. 初始化

真正执行编写的java程序代码,对类的静态变量进行初始化。与3中的初始化不同:3将静态变量初始化为默认值,例如整型则初始化为0;5将依据声明时指定的初始值、静态初始化块对静态变量进行初始化。

初始化的时机:
1. 创建类的实例时:通过new创建、通过反射创建、通过反序列化创建
2. 调用类的静态方法、访问或修改类的静态变量
3. 使用java.lang.reflect包的方法对类型进行反射调用时
4. 初始化某个类的子类,其所有父类都会被初始化
5. 直接使用java.exe运行某个主类,虚拟机会先初始化这个主类。
6. 当接口中包含default方法,如果这个接口的实现类进行了初始化,则这个接口要在其前被初始化

以上6种触发类初始化的方法成为主动引用。除此之外,所有引用类型的方式都不会触发初始化,称为被动引用:

  1. 通过子类引用父类的静态字段,不会导致子类初始化
  2. 通过数组定义引用类,不会触发此类的初始化
  3. 常量在编译阶段会进入类的常量池,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化

类加载器

类加载器负责将class文件加载到内存中,并为其生成对应的java.lang.Class对象。共有4类类加载器:

  1. Bootstrap ClassLoader:启动类加载器
  2. Extension ClassLoader:拓展类加载器
  3. Application ClassLoader:应用类加载器
  4. User ClassLoader: 自定义类加载器
    jvm之类加载机制_第2张图片

类加载机制:

  1. 全盘负责
    当一个类加载器负责加载某个Class时,该Class所依赖和引用的Class也由该类加载器负责,除非显式地使用另一个类加载器
  2. 双亲委托
    先让父加载器试图加载该Class,只有在父类加载器无法加载该Class时才尝试从自己的路径下加载
  3. 缓存机制
    所有加载过的类都会被缓存,当程序需要某个Class时,类加载器先从缓存中搜寻该Class,当不存在该Class时才进行加载。这也是修改Class后必须重新启动JVM,修改才生效的原因。

双亲委托的好处

  1. 沙箱安全机制:自己写的核心类和拓展类不会被加载,可以防止核心API被随意篡改

  2. 避免类的重复加载:当父亲已经加载了该类时,子类加载器不会重新加载一次

相关问题

1. new 一个对象背后发生了什么

2. 下面这段代码能运行吗?为什么

package java.lang;

public class String {
	public static void main(String[] args) {
		System.out.println("string");
	}
}

不能。报错如下:

java.lang.NoSuchMethodError: main
Exception in thread "main"

原因在于类加载机制中的双亲委托机制。根据双亲委托,在加载该类时会由Bootstrap ClassLoader进行加载且加载的是java核心库中的java.lang.String并非自定义的java.lang.String。核心库中的java.lang.String并没有Main方法所以会抛出NoSuchMethodError。

3. 能不能自定义一个类叫java.lang.System

看了第2题你可能会说不能,但是其实也能,通过自定义类加载器绕过双亲委托机制。

你可能感兴趣的:(java)