JVM —— 类加载器子系统

类加载的过程

image.png

  1. 加载
    1. 通过一个类的全限定名获取定义此类的二进制字节流
    2. 将这个字节流所代表的静态存储结构转化为方法去运行时的数据结构
    3. 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口;
  2. 链接
    1. 验证        目的在于确保 Class 文件的字节流中包含信息符合当前虚拟机的要求,保证被加载类的正确性,不会危害虚拟机自身安全
    2. 准备        为类变量分配内存并且设置该类变量的默认初始值,即零值。这里不包含用 final 修饰的 static,因为 final 编译的时候就会分配了,准备阶段会显式初始化;这里不会为实例变量分配初始化,类变量分配在方法区中,而实例变量是会随着对象一起分配到 Java 堆中;
    3. 解析        将常量池内的符号引用转换为直接引用的类型;解析操作往往会伴随着 JVM 在执行完之后再执行;
  3. 初始化        初始化阶段就是执行类构造器方法<clinit>()的过程;此方法不需定义,是 javac 编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来;指令按照语句在原文件中的顺序执行。<clinit>()不同于类的构造器。若该类有父类,JVM会保证子类的<clinit>()执行之前,父类的<clinit>()已经执行完毕。虚拟机必须保证一个类的<clinit>()方法在多线程下呗同步加锁。

双亲委派机制

  • 什么是双亲委派机制?
    • 当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载器中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的 Class),子类加载器才会尝试自己去加载。
    • 例如当我们自己在 java.lang 包下写一个String类,然后在别的类里面 new String(); 执行过程是:系统类加载器接到加载请求,但是不进行加载,先给其父类的扩展类加载器,扩展类加载器也同样委派给启动类加载器,启动类加载器收到之后查路径,会查到系统的String类,所以最后加载的是系统的String类,而不是我们自己定义的。
  • 优点
    • 避免类的重复加载
    • 保护程序安全,防止核心API被随意篡改

沙箱安全机制

双亲委派中不会加载自定义的 String 类,而是加载了系统的 String 类,这样可以保护对Java核心源代码的保护,这就是沙箱安全机制。

其他补充

  • JVM中表示两个 class 对象是否为同一个类存在两个必要条件:
    • 类的完整类名必须一致,包括包名;
    • 加载这个类的 classLoader (指 ClassLoader 实例对象)必须相同。 
  • 类的主动使用,类的初始化的七种情况:
    • 创建类的实例;
    • 访问某个类或接口的静态变量,或者对该静态变量赋值;
    • 调用类的静态静态方法;
    • 反射(比如;Class.forName("com.atguigu.Test"));
    • 初始化一个类的子类;
    • Java虚拟机启动时被注明为启动类的类;
    • JDK 7 开始提供的当他语言支持;
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值