学习笔记(第1天)JVM-类加载子系统

前言

最近开始复习过去学过的知识加学习新的知识,就打算通过写博客来进行整理和加深印象。属于个人笔记类型,完全可以说是写给自己看的(笑),不过也希望自己总结的东西能帮到其他人吧,

一、类加载子系统

负责从文件系统或者网络中加载Class文件(class文件在文件开头有特定的文件标识:CA FE BA BE)。只负责Class文件的加载,不负责是否可以运行(运行由执行引擎负责)。加载的类信息(DNA元数据模板)存放于方法区中
在这里插入图片描述

1.类的加载过程

(注:上下文的两个加载代表含义并不相同

(1)Loading(加载)(生成Class实例)
a.通过一个类的全限定名获取定义此类的二进制字节流(从硬盘加载进内存)

b.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

c.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

(2)Linking(链接)

①验证:确保Class文件的字节流中包含信息符合当前虚拟机要求, 保证被加载类的正确性,不会危害虚拟机自身安全

a.文件格式验证
b.元数据验证
c.字节码验证
d.符号引用验证

②准备:

a.为类变量(静态【static】变量)分配内存并且设置该变量的默认初始值,即零值(在初始化阶段才会设置为用户定义的值,且此时变量不可被调用

b.不包含用final修饰的static(即常量),因为final在编译的时候就会分配,准备阶段会显式初始化

c.不会为实例变量分配初始化(因为此时还未创建对象),类变量会分配在方法区中,而实例变量是会随实例对象分配到Java堆中

③解析:

a.将常量池内的符号引用转换为直接引用的过程。

b.事实上,解析往往会伴随着JVM在执行完初始化之后再执行

c.符号引用就是一组符号来描述所引用的目标,符号引用的字面量形式明 确定义在《Java虚拟机规范》的Class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

d.解析动作主要针对类或接口,字段,类方法,接口方法,方法类型等,对应常量池中的 CONSTANT_Class_inf,CONSTANT_Fieldref_info,CONSTANT_Methodref_info等。

(3)IntiaLization(初始化)

a.初始化阶段就是执行类构造方法()的过程(若类中没有设置static的变量或方法块,则不会产生()

b.此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来

c.构造方法中指令按语句在源文件中出现的顺序执行

d.()不同于类的构造器。(关联:构造器是虚拟机视角下的(),每个类至少存在一个构造器)

e.若该类具有父类,JVM会保证子类的()执行前,父类的()已经执行完毕

2.类加载器的分类

(1)引导类加载器

(2)自定义类加载器:所有派生于抽象类ClassLoader的类加载器都划分为自定义加载器

3.常见类加载器

系统类加载器(java编写)->扩展类加载器(java编写)->引导类加载器(由C/C++编写的)
(箭头指的是包含关系,不是继承关系)
(对于用户自定义类,默认使用系统类加载器进行加载
(Java核心类库都是使用引导类加载器进行加载

(1)引导类加载器(启动类加载器)
a.该加载器使用C/C++实现,嵌套在JVM内部

b.用来记载Java的核心库,用于提供JVM自身需要的类

c.不继承自java.lang.ClassLoader,没有父加载器此处父加载器并非指子父类的继承关系,而是类似超类的关系,下文出现的父类加载器含义也亦是如此

d.加载扩展类和应用程序类加载器,并指定为他们的父类加载器

e.出于安全考虑,引导类加载器只加载包名为java,javax,sum等开头的类

(2)扩展类加载器

a.Java语言编写,由sum.misc.Launcher$ExtClassLoader实现

b.派生于ClassLoader类

c.父类加载器为引导类加载器

d.从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安全目录的jre/lib/ext子目录(扩展目录)下加载。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载.

(3)系统类加载器(应用程序类加载器)
a.Java语言编写,由sum.misc.Launcher$AppClassLoader实现

b.派生于ClassLoader类

c.父类加载器为引导类加载器

d.负责加载环境变量classpath或系统属性Java.class.path指定路径下的类库

e.是程序中默认的类加载器,Java应用的类一般都是由它来加载

f.通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器

(4)用户自定义类加载器
①什么时候需要自定义类加载器
a.隔离加载类

b.修改类加载的方式

c.扩展加载源

d.防止源码泄露

②简单实现步骤

a.可以通过继承抽象类java.lang.ClassLoader类实现

b.JDK1.2前采用重写loadClass()方法,JDK1.2后建议采用把自定义的类加载逻辑写在findClass()方法中

c.若没有太过于复杂的需求,可以直接继承URLClassLoader类,可以避免自己去编写findClass()方法及其获取字节流的方式

相关知识点补充

一、双亲委派机制
1.工作原理
1)如果一个类加载器收到了类加载请求,不会自己先去加载,而是把这个请求委托给父类的加载器去执行。

2)如果父类加载器还存在其父类加载器,则进一步向上委托,请求最终将到达顶层的启动类加载器。

3)如果父类加载器可以完成类加载任务,就成功返回,如果无法完成,子加载器才会尝试自己去加载。

此图不考虑自定义类加载器的情况注:此图不考虑自定义类加载器的情况

2.优势
1)避免类的重复加载
各个类加载器具有层次关系,一旦父类加载器进行 加载,则子加载器不会再去加载类,可避免类的重 复加载。

2)保护程序安全,防止核心API被修改
防止自定义类与核心API中的同名类产生冲突,使 核心API被修改破坏。双亲委派机制使得核心API 会优先于自定义类被加载。

3.沙箱安全机制
保护核心API不受自定义类的影响和破坏。比如用户自定义了一个java.lang.String类,并写了main方法,在双亲委派机制下,虚拟机会加载的是核心API的String类,此时会报错说String类中并不存在main方法。从而实现了对核心API的保护。

二、在JVM中表示两个class类对象是否为同一个类的必要条件
1.两个类的完整类名必须一致,包括包名

2.加载这两个类的ClassLoader(指实例对象)必须相同。

三、对类加载器的引用
1.JVM必须知道一个类型是由启动加载器(引导加载器)加载还是由用户类加载器(系统加载器)加载。

2.如果是由用户类加载器加载,JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。

3.从解析一个类型到另一个类型的引用的时候JVM需要保证这两个类型的类加载器是相同的。

四、类的主动使用和被动使用
1.主动使用(会导致类的初始化
①创建类的实例

②访问某个类或接口的静态变量,或者对该静态变量赋值

③调用类的静态方法

④反射

⑤初始化一个类的子类(因为父类会先被初始化)

⑥Java虚拟机启动时被标明为启动类的类

⑦JDK 7开始提供的动态语言支持

2.被动使用(不会导致类的初始化)
除了上述七种情况,其他使用Java类的方式都被看做是类的被动使用。

结语

第一次写博客,如果有哪里出错或者不达意的地方请指出来,我会立刻修正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值