Java类加载是什么意思

发布时间:2021-06-23 14:47:00 作者:chen
来源:亿速云 阅读:222

本篇内容介绍了“Java类加载是什么意思”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1 来源

2 类加载简介

类加载的过程可以简单分为三个阶段:

3 主动使用与被动使用

JVM规范规定了每个类或接口在首次主动使用的时候都需要进行初始化,规定了以下六种主动使用类的场景:

除了以上六种情况外,其余的都叫被动使用,不会导致类的加载和初始化,比如引用类的静态常量不会导致类的初始化。

4 类加载详解

前面也说了类加载可以简单分为三个阶段:

下面先来看一下加载阶段。

4.1 加载阶段

加载阶段就是将class文件中的二进制数据读取到内存之中,然后将该字节流代表的静态存储结构转换为方法区中运行时数据结构,并且在堆中生成一个该类的java.lang.Class对象,作为访问方法区数据结构的入口。

类加载的最终产物就是堆内存中的class对象,JVM规范中指出类加载是通过一个全限定名去获取二进制数据流,来源包括:

类加载阶段结束后,JVM会将这些二进制字节流按照JVM定义的格式存放在方法区中,形成特定的数据结构后再在堆内存中实例化一个java.lang.Class对象。

4.2 连接阶段

该阶段可以分为三个小阶段:

需要注意的是这三个小阶段其实不是顺序进行的,而是交叉着进行的,也就是解析的时候其实也会有验证的过程。

4.2.1 验证

验证是为了确保字节流所包含的内容符合JVM规范,并且不会出现危害JVM自身安全的代码,当字节流信息不符合要求的时候,会抛出VerifyError这样的异常或其子异常,验证的信息包括:

4.2.1.1 验证文件格式

包括:

4.2.1.2 验证元数据

元数据验证其实是进行语义分析的过程,语义分析是为了确保字节流符合JVM规范要求,包括:

4.2.1.3 验证字节码

字节码验证主要是验证程序的控制流程,包括:

4.2.1.4 验证符号引用

验证符号引用转换为直接引用的合法性,保证解析动作的顺利执行,包括:

4.2.2 准备

经过验证后,就开始了准备阶段,这阶段比较简单,就是对对象的静态变量分配内存并且设置初始值,类变量的内存会被分配到方法区中。设置初始值就是为相应的类变量给定一个相关类型在没有被设置时的默认值,比如Int的初始值为0,引用的初始值为null

4.2.3 解析

解析就是在常量池中寻找类、字段、接口和方法的符号引用,并且将这些符号引用替换成直接引用的过程。解析主要针对类接口、字段、类方法和接口方法进行的,包括:

4.3 初始化阶段

初始化阶段主要就是执行<clinit>方法的过程,该方法是编译阶段生成的,也就是说包含在字节码文件中,该方法包含了所有类变量的赋值动作和静态语句块的执行代码。另一方面,<clinit>与构造方法不同,不需要显式调用父类构造器,虚拟机会保证父类的<clinit>方法最先执行。

还需要注意的是<clinit>只能被虚拟机执行,虚拟机还会保证多线程下的安全性,因此,如果在静态代码块中如果包含了加载其他类的操作可能会引起死锁,例子可以看这里。

5 类加载器

5.1 JVM中的三类核心类加载器

JVM中有三类核心类加载器,分别是:

5.2 双亲委派机制

一个类加载器加载一个类的时候,并不会尝试直接加载该类,而是先交给父加载器尝试加载,一直到顶层的父加载器(启动类加载器),如果父加载器加载失败,则会自己尝试加载,图示如下:

Java类加载是什么意思

6 线程上下文类加载器

JDK中提供了很多SPIService Provider Interface),比如JDBC等,JDBC只规定了这些接口之间的逻辑关系,但不提供具体的实现,换句话说,JDBC完全透明了应用程序和第三方厂商数据库驱动的具体实现,应用程序只需要面向接口编程即可。但问题是:

由于双亲委派机制,ConnectionsStatement等都是由启动类加载器加载,而第三方JDBC驱动包中的实现不会被加载。解决这个问题的关键,就是使用了线程上下文类加载器打破了双亲委派机制。

比如MySQL驱动的加载过程,就是通过线程上下文类加载器加载的,

private static Connection getConnection(String url, Properties info, Class<?> caller) throws SQLException {
        //...
        if (callerCL == null || callerCL == ClassLoader.getPlatformClassLoader()) {
            callerCL = Thread.currentThread().getContextClassLoader();
        }
		while(true) {
			//...
			if (isDriverAllowed(aDriver.driver, callerCL)) {
			}
		}
		//...
}
private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
	//...
    try {
        aClass = Class.forName(driver.getClass().getName(), true, classLoader);
    } catch (Exception var5) {
        result = false;
    }
    //...
    return result;
}

通过线程上下文类加载器,就变成了启动类加载器去委托子类加载器去加载实现的方式,也就是JDK自己亲自打破了双亲委派机制这种方式,这种加载方式几乎涉及所有的SPI加载,包括JAXBJCEJBI等。

“Java类加载是什么意思”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

推荐阅读:
  1. Java的类加载机制是什么
  2. java类加载机制是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:Perl中如何使用标量转换函数

下一篇:Perl中怎么格式化输出

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》