jvm类的加载机制_java类加载流程及原理

jvm类的加载机制_java类加载流程及原理1.类加载器的组织结构转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52301541类加载器ClassLoader是具有层次结构的,也就是父子关系。其中,Bootstrap是所有类加载器的父亲。(1)Bootstrapclassloader:启动类加载器当运行Java虚拟机时,这个类加载器被创建,…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1. 类加载器的组织结构

转载请注明出处:JVM——Java类加载机制总结_SEU_Calvin的博客-CSDN博客

类加载器 ClassLoader是具有层次结构的,也就是父子关系。其中,Bootstrap是所有类加载器的父亲

(1)Bootstrapclass loader 启动类加载器

当运行Java虚拟机时,这个类加载器被创建,它负责加载虚拟机的核心类库,如java.lang.*等。

(2)Extensionclass loader:标准扩展类加载器

用于加载除了基本 API之外的一些拓展类

(3)AppClassLoader加载应用程序和程序员自定义的类

运行下面的程序,结果也显示出来了:

jvm类的加载机制_java类加载流程及原理

从运行结果可以看出加载器之间的父子关系,ExtClassLoader的父Loader返回了null

原因是BootstrapLoader(启动类加载器)是用C语言实现的,找不到一个确定的返回父Loader的方式。

2. 类的加载机制

类被加载到虚拟机内存包括加载、链接、初始化几个阶段。其中链接又细化分为验证、准备、解析。

这里需要注意的是,解析阶段在某些情况下可以在初始化阶段之后再开始,这是为了支持Java的运行时绑定。各个阶段的作用整理如下:

 

2.1 加载阶段

加载阶段可以使用系统提供的类加载器(ClassLoader)来完成,也可以由用户自定义的类加载器完成,开发人员可以通过定义类加载器去控制字节流的获取方式

1通过类的全名产生对应类的二进制数据流

2)将这些二进制数据流转换为方法区的运行时数据结构

3)创建代表这个类的java.lang.Class对象。作为方法区这些数据的访问入口

 

2.2 链接阶段(实现 Java 的动态性的重要一步)

1验证:验证阶段的主要目的是确保class文件字节流的正确性,要验证比如class文件格式规范、这个类是否继承了final类、不能把一个父类对象赋值给子类数据类型等等。

2准备:准备阶段为方法区中的静态变量分配内存空间。并将其赋值为初始值,所有原始类型的值都为0。如float0f int0boolean0、引用类型为null

3解析:解析阶段把符号引用解析为直接引用

符号引用是一个字符串,它唯一标识一个类、一个字段、一个方法等目标。

而直接引用对于类变量、类方法指的是指向方法区的指针,然后对于实例方法、实例对象来说就是偏移量,比如一个实例方法,子类中方法表中的偏移量和父类是一致的,这个偏移量可以确定某个方法的位置。

 

2.3 初始化

到了初始化阶段,才是真正执行用户定义程序代码。在初始化阶段就是执行类构造器方法的过程,工作包括赋值类变量、静态语句块的合并

//定义在静态语句块之后的变量可以赋值,但不能访问
public class Test{
    static{
        i=0;//給变量赋值,可以通过编译
        System.out.print(i);//这句编译器会提示非法向前引用
    }
    static int i=1;
}

初始化过程会被触发的条件汇总:

1)使用new关键字实例化对象、访问一个类的静态字段静态方法的时候。

2对类进行反射调用的时候。

3)当初始化子类时,如果发现其父类还没有进行过初始化,则进行父类的初始化

 

【关于构造器方法拓展知识】(可以不看)

1)类构造器<clinit>()方法与类的构造函数不同,它不需要显式调用父类构造,虚拟机会保证在子类<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。因此在虚拟机中的第一个执行的<clinit>()方法的类肯定是java.lang.Object

2)由于父类的<clinit>()方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作。

3<clinit>()方法不是必须的,如果一个类中没有静态语句,那么编译器可以不为这个类生成<clinit>()方法。

4接口中不能使用静态语句块,和类不同的是,执行接口的<clinit>()方法不需要先执行父接口<clinit>()方法。只有当父接口中定义的变量被使用时,父接口才会被初始化。另外,接口的实现类在初始化时也一样不会执行接口的<clinit>()方法。

5)虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步,可能会导致阻塞。

3. 类加载的三种方式

1)由 new 关键字创建一个类的实例。

2)调用 Class.forName() 方法,通过反射加载类。

3)调用某个ClassLoader实例的loadClass()方法。

 

三者的区别汇总如下:

1)方法12都是使用的当前类加载器。方法3是用户指定的类加载器加载

2)方法1是静态加载,23是动态加载。

3)对于两种动态加载,如果程序需要类被初始化,就必须使用Class.forName(name)的方式

Class.forName(className);
//实际上是调用的是:
Class.forName(className, true, this.getClass().getClassLoader());//第二个参为true即默认类需要初始化,初始化会触发目标对象静态块的执行和静态变量的初始化
ClassLoader.loadClass(className);
//实际上调用的是:
ClassLoader.loadClass(name, false);//第二个参数即默认得到的class还没有进行链接,意味着不进行初始化等系列操作,即静态代码块不会执行

jvm类的加载机制_java类加载流程及原理

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/169728.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号