JVM之类加载机制

什么是JVM?

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
来自:https://baike.baidu.com/item/JVM/2902369?fr=aladdin

类加载机制

什么是类加载机制
  过程:在JAVA代码中,类的加载,连接,初始化过程都是程序运行时完成的

1.加载:

  类加载器(机制:双亲委托或叫父亲委托,全盘委托,缓存加载)
    1.根类加载器:可以在你安装的java的目录下的jre下的lib的rt.jar包中看到,比如说String类
在这里插入图片描述
或者也可以在IDE工具里面进行相应的代码查看

package test;

public class TestLoad {
    public static void main(String[] args) {
               Class c= String.class;
               System.out.println(c.getClassLoader());
    }
}

运行后可以看到结果为null,这里因为根类加载器是看不到的
在这里插入图片描述

    2.拓展类加载器:加载的是Java\jre1.8.0_251\lib\ext下的,我们现在就使用一下这个文件夹里面的某个类

package test;

import sun.util.resources.cldr.CalendarData;

public class TestLoad2 {
    public static void main(String[] args) {
       Class c= CalendarData.class;
       System.out.println(c.getClassLoader());
    }
}

运行代码可以看到
在这里插入图片描述

    3.应用类加载器:加载的就是我们自己项目写的类,也就是项目的classpath下的,比如:

package test;

import sun.util.resources.cldr.CalendarData;

public class TestLoad2 {
    public static void main(String[] args) {
       Class c= TestLoad2.class;
       System.out.println(c.getClassLoader());
    }
}

运行:
在这里插入图片描述

    自定义加载器:加载的是外部的类文件,例如IDE工具的热部署就用到了,暂时没有学习这一块,以后会了加上

加载的作用是查找并加载类的二进制数据


类加载过程中做了什么?

  1.通过一个类的全限定名称获取其定义的二进制流
  2.将这个字节流所代表的静态存储结构转化为方法区,类的运行时数据结构
  3.在java方法区中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口

加载完成后,虚拟机外部的二进制流就会按照虚拟机所要求的格式存储在方法区中,在Java堆中也会创建一个java.class对象,通过这个对象访问到方法区中的数据


2.连接:

 1.验证:确保被加载的类的正确性(运行生成后的字节码文件(class文件)可以人为的进行修改)
 2.准备:为类的静态变量分配内存(共享内存,因为静态变量是类的),并将其初始化默认值(就算你显示的赋了值,还是会赋为默认值)
在这里插入图片描述
这里需要注意的是引用类型占4个字节

 3.解析:将类中的符号引用转化为直接引用
在这里插入图片描述
然后切换到已经生成好的class文件的目录下,例如我这里要去test下
在这里插入图片描述
然后使用javap -v class文件名称
在这里插入图片描述
像这里的这个#6,#23啊什么的就是符号引用
在这里插入图片描述
如果出现这个错误,则去看你的环境变量中path是否有%JAVA_HOME%\bin,没有则添加上
在这里插入图片描述

准备阶段和解析阶段的顺序可能不一致


3.初始化:

 作用:为类的静态变量赋予正确的初始值(就是在准备阶段就算你显示的赋了值也是默认值,在初始化阶段才会赋你显示赋的值。静态代码块也是在这个阶段执行的)


4.使用:

 java程序对类的使用方法可分为两种
  1.主动使用:

    1.创建类的实例对象
    2.访问某个类的或者接口的静态变量,或者对该静态变量赋值
    3.调用类的静态方法
    4.通过反射动态加载某个类
    5.初始化一个类的子类
    6.Java虚拟机启动时被表明为启动类的类
    7.JDK1.7的时候出现Java反射动态方法的调用


  2.被动使用:

    1.通过子类引用父类的静态字段,是子类的被动使用,不会导致子类初始化
    2.通过数组定义类引用类,是类的被动使用,不会触发此类的初始化
    3.常量在编译阶段会存入调用方法所在的类的常量池中,本质上,没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化(如果在编译时值就定死了,就不会主动使用,如果是运行时才确定值,就会进行主动使用)

所有的Java虚拟机实现必须在每个类或接口被Java程序"首次主动使用"时才会初始化它们(只有满足主动使用的条件才能进行初始化。可能 加载进来了,但不会初始化)

被动使用不会初始化类,但是有可能会加载类


主动使用和被动使用的各种例子:https://editor.csdn.net/md/?articleId=106480159


-XX:+TraceClassLoading:加载的类的顺序的命令
例:

package accord;

/**
 * 常量是被动使用
 *原因:常量在编译阶段就已经放入到内存去了,值已经确定了
 *
 * 被动使用不会初始化类,但是有可能会加载类
 */
public class Test6 {
    public static void main(String[] args) {
        System.out.println(InnerClass.STR);
    }
}

class InnerClass{
    public static final String STR="hello";

    static{
        System.out.print("InnerClass static....");
    }
}

在这里插入图片描述

在这里插入图片描述
运行后可以看到依次加载的类
在这里插入图片描述
可以看到我们的Test6已经被加载了,但是InnerClass并没有被加载
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值