7 类加载

过程:加载->验证->准备->解析->初始化->使用->卸载

链接阶段:验证 准备 解析

7.1 加载

通过全类名获取定义此类的二进制字节流(这里我们可以在硬盘,网络,运行时动态生成都行,只要我们能得到并转换成jvm的字节码规定的格式就行)。
将字节流所代表的静态存储结构转换为方法区的运行时数据结构
在内存中生成一个代表该类的 java.lang.Class 对象,作为方法区这些数据的访问入口

image-20230325005029560

image-20230325005050454

类被加载的时机:

一、定义了main的类,启动main方法时该类会被加载

二、创建类的实例,即new对象的时候
此时被加载的类有Father及Field类,我们重启服务,然后去访问创建子类的实例。为什么要重启呢?因为每个类在虚拟机生命周期中如果存在,则不会重复加载。不重启的话,看不到我们想要的效果。

2、创建子类的实例
在创建子类实例的时候,在加载子类之前会优先加载其父类。

三、访问类的静态方法

四、访问类的静态变量

五、反射 Class.forName()

7.2 验证

验证阶段主要是对class文件作校验,主要分为:文件格式校验、字节码校验、元数据验证、符号引用验证。保证类加载的正确性且执行class文件时不会对jvm本身造成危害。

7.3 准备

这个阶段是给类变量(static修饰的变量存放于方法区中)设置初始值。注意是设置初始值,比如int类型的初始值是0。
public static int value = 123;
而下面的
public static final int value = 123;
则是编译时javac会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ContstantVlue的设置将value的数值设置为123

7.4 解析

解析就是把把在常量池中的符号引用替换为直接引用的过程。通俗点就是能够在常量池中的符号引用直接指向目标的指针,这样就能够映射到符号引用代表的对象的内存地址。用linux中的软链接和硬链接来解释,符号引用指向一个路径,类似快捷方式,直接引用指向一个INODE,一个用操作系统的术语来说就是该进程的逻辑地址。

7.5 初始化

初始化阶段是根据程序员通过程序制定的主观计划去初始化类变量和其他资源。通俗点讲就是给类变量赋我们给的值,和执行static语句块里面的内容。
那什么时候一个类会进行初始化呢?总结得出以下几点。

new一个对象
读取或者设置一个类的静态字段(被final修饰,已在编译期把结果放在常量池除外)
调用一个类的静态方法
通过反射调用
当初使化一个类的时候,如果发现其父类还没有进行初始化,那么需先初始化这个父类
执行main()方法

上面说的这几点属于对类的主动引用,有且只有这几种方式属于主动引用,其他称为被动引用,被动引用不会引发类的初始化。

image-20230325220924475

7.6 使用懒惰加载器来实现单例模式

image-20230325223618573

没有用到内部静态类时,是不会触发类加载的

jvm在加载类的时候,会保证**线程安全

 posted on 2023-03-27 22:16    阅读(13)  评论(0编辑  收藏  举报