(转) JVM——Java类加载机制总结

背景:对java类的加载机制,一直都是模糊的理解,这篇文章看下来清晰易懂。

转载:http://blog.csdn.net/seu_calvin/article/details/52301541

1. 类加载器的组织结构

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

(1)Bootstrapclass loader: 启动类加载器

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

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

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

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

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

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

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

2. 类的加载机制

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

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

2.1 加载阶段

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

ps:可以自定义类加载器,从加密和安全两个角度出发来加载特殊的类。具体参考——

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

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

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

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

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

(2)准备:准备阶段为方法区中的静态变量分配内存空间。并将其赋值为初始值,所有原始类型的值都为0。如float为0f、 int为0、boolean为0、引用类型为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)方法1和2都是使用的当前类加载器。方法3是由用户指定的类加载器加载。

(2)方法1是静态加载,2、3是动态加载。

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

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

原文地址:https://www.cnblogs.com/lixuwu/p/8492258.html

时间: 2024-10-11 17:01:30

(转) JVM——Java类加载机制总结的相关文章

Java类加载机制与反射 jvm学习

同一个JVM的有线程.所有变量都处于同一个进程里,他们都使用JVM进程的内存区.当系统出现以下几种情况时JVM进程将被终止: 1.程序运行到最后正常结束 2.程序运行到使用System.exit()或Runtime.getRuntime().exit)代码处结束程序. 3.程序执行过程中遇到未捕获的异常或错误而结束. 4.程序所在平台强制结束了JVM进程 注意两次运行java程序,处于两个不同的JVM他们不共享内存. 类的加载 1.当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过加

jvm之java类加载机制和类加载器(ClassLoader)的详解

当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化. 一.类加载过程 1.加载 加载指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象. 类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础

Java类加载机制的深入研究

类加载机制 类加载是Java程序运行的首要步骤,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行,同时让程序能动态的控制类加载,比如热部署等,提高程序的灵活性和适应性. 类加载过程 Java程序运行的场所是内存. 当在命令行执行java HelloWorld的时候,JVM会将HelloWorld.class加载到内存中,形成一个class对象:HelloWorld.class,具体过程如下: 1.找到jre目录,找到jvm.dll文件,并且初始化JVM 2.产生一个

深入理解和探究Java类加载机制-

深入理解和探究Java类加载机制---- 1.java.lang.ClassLoader类介绍 java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 java.lang.Class类的一个实例. ClassLoader提供了一系列的方法,比较重要的方法如: 2.JVM中类加载器的树状层次结构 Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写

深入JVM之类加载机制

JVM系列 1.深入JVM之源码编译机制 2.深入JVM之类加载机制 3.深入JVM之类执行机制 4.JVM内存诊断工具 总结下类加载机制相关的知识图谱. 转载请注明出处:http://blog.csdn.net/supera_li/article/details/45747329 类加载机制,包括三大步骤. 1.装载load .目的是生成类加载实例id 2.链接 ,检测字节码格式以及内部调用匹配情况.静态变量初始化 3.初始化.主要是类加载器加载类的顺序. 对于自定义类加载,开发者完成自己的实

JVM之类加载机制

JVM之类加载机制 JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 类加载五部分 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的入口.注意这里不一定非得要从一个Class文件获取,这里既可以从ZIP包中读取(比如从jar包和war包中读取),也可以在运行时计算生成(动态代理),也可以由其它文件生成(比如将JSP文件转换成对应的Class类). 验证 这一阶

两道面试题,带你透彻解析Java类加载机制

在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Grandpa { static { System.out.println("爷爷在静态代码块"); } } class Father extends Grandpa { static { System.out.println("爸爸在静态代码块"); } public static int factor = 25; public Father() { System.ou

用两道面试题带你详细了解 Java 类加载机制

在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Grandpa{static{System.out.println("爷爷在静态代码块");}} class Father extends Grandpa{static{System.out.println("爸爸在静态代码块");}public static int factor = 25;public Father(){System.out.println("

一文读懂Java类加载机制

Java 类加载机制 Java 类加载机制详解. @pdai Java 类加载机制 类的生命周期 类的加载:查找并加载类的二进制数据 连接 验证:确保被加载的类的正确性 准备:为类的静态变量分配内存,并将其初始化为默认值 解析:把类中的符号引用转换为直接引用 初始化 使用 卸载 类加载器, JVM类加载机制 类加载器的层次 寻找类加载器 类的加载 JVM类加载机制 自定义类加载器 参考文章 类的生命周期 其中类加载的过程包括了加载.验证.准备.解析.初始化五个阶段.在这五个阶段中,加载.验证.准