JVM 之类加载器

一、什么是 JVM

  JVM(Java Virtual Machine)是一个可以执行 Java 字节码文件(即 .class 文件)的虚拟机进程。当 Java 源文件能被成功编译成 .class 文件,就能在不同平台上的不同版本的 JVM 运行,因为 JVM 能将相同的 .class 文件解释称不同平台的机器码。正是因为 JVM 的存在,Java 被称为与平台无关的语言。

  一般而言,.java 文件经过编译后会得到 .class 文件,而将这个文件加载到内存之前需要先通过类加载器,先简单过一下图:

            

二、类加载过程

  类加载的过程为: 加载-->连接(验证-->准备-->解析)-->初始化。下面介绍其中的几个过程。

 1、加载

  这个过程主要是通过类的全限定名,例如 java.lang.String 这样带上包路径的类名,获取到字节码文件;然后将这个字节码文件代表的静态存储结构(可简单理解为对象创建的模板)存在方法区,并在堆中生成一个代表此类的 Class 类型的对象,作为访问方法区中“模板”的入口,往后创建对象的时候就按照这个模板创建。

  举个例子,有时候通过反射创建对象,像当初学 JDBC 时会通过 Class.getName("com.mysql.jdbc.Driver.class").newInstance() 创建对象,通过 Class 和相应的全限定类名获取到方法区中的“模板”然后创建对象。

        

 2、验证

  验证过程主要确保被加载的类的正确性。首先要先验证文件格式是否规范,如果只是通过 .class 后缀来辨别,那随便把后缀名改一下就可以跑程序了,那岂不是很容易出事。来看看字节码文件大概是长什么样的:

       

  注意看前缀 cafe babe(咖啡宝贝?)这只是验证的其中一个点,还会验证字节码文件里是否包含主次版本号等验证信息。

 3、准备

  这个阶段主要是给类变量(静态变量)分配方法区的内存并初始化。实例变量不是在这个阶段分配内存,实例变量是随着对象一起分配在堆中。另外,给静态变量初始化为零值或空值,比如public static int n=5;这里并不是马上给 n 这个变量赋值为 5,而是先将其赋值为 0,类似的,如果是引用数据类型,则默认为 null。还有一点需要注意的是,对于 final 类型的数据,必须在程序内给它赋值,系统不会自动初始化,例如 static String str = "hello" + “world”;String 是 final 类型的,在编译阶段就给它优化成 static String str = "helloworld” ,并且将 "helloworld" 放进了常量池。

 4、初始化

  这个阶段就是将静态变量赋值为初始值,还是 public static int n=5; 这回给 n 赋值为 5 了。

三、类加载器

        

  启动类加载器是由C/C++写的,主要负责加载 jre\lib 目录下的类;扩展类加载器主要负责加载 jre\lib\ext 目录下的类;而应用程序类加载器主要负责加载我们自己编写的类;当然还能自己写类加载器,即自定义加载器。程序主要由前面三个类加载器相互配合加载的。

public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        System.out.println(main.getClass().getClassLoader());
        System.out.println(main.getClass().getClassLoader().getParent());
        System.out.println(main.getClass().getClassLoader().getParent().getParent());
    }
}  

  由于启动类加载器是 C/C++ 语言写的,所以输出为 null

 双亲委派机制

  在类加载的过程中,存在着双亲委派机制,即当要加载一个类时,先由父类加载器加载,当父类加载器没办法加载时,才由下面的加载器加载,来看一个程序:

package java.lang;   // 自定义的包

public class String {
    public static void main(String[] args) {
        System.out.println("这是自定义的java.lang.String类");
    }
}

  

  由于 jre\lib\ext 中存在 java.lang.String 类,当加载该类的时候,根据全限定名进行查找,找到后由启动类加载器加载,发现 String 类中不包含 main() 方法,因此程序出错。

原文地址:https://www.cnblogs.com/lyuzt/p/12057385.html

时间: 2024-10-23 22:08:52

JVM 之类加载器的相关文章

JVM自定义类加载器加载指定classPath下的所有class及jar

一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责JAVA_HOME/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作. 2.其他类加载器:由java实现,可以在方法区找到其Class对象.这里又细分为几个加载器 a).扩展类加载器(Extension ClassLoader):负责用于加载JAVA_HOM

jvm自定义类加载器

除了自定义的类加载之外,jvm存在三种类加载器,并以一种父委托的加载机制进行加载. --启动类加载器,又称根加载器,是一个native的方法,使用c++实现.在java中我们用null标识,用于加载jdk自带的类. --扩展类加载器,用于加载jdk扩展类 --系统类加载器,用于加载classpath目录下的类 上面提到的三种类加载器,是存在父子关系,即系统类加载器会委托extension加载器,如果extension加载器不能加载该类的话,再由系统类加载器进行加载.注意这里所说的父子关系不是指继

JVM之类加载器

一.首先,小小测试,看是否已经掌握了JVM类加载的过程 1.1.测试一: class Singleton { private static Singleton sin = new Singleton(); public static int counter1; public static int counter2 = 0; private Singleton() { counter1++; counter2++; } public static Singleton getInstance() {

jvm之类加载器-《疯狂java讲义》

1. 类加载器简介 类加载器负责加载所有的类,系统为所有被载入内存中的类生成一个java.lang.Class实例.一旦一个类被载入JVM中,同一个类就不会被再次载入了.现在的问题是怎么样才算“同一个类”?正如一个对象有一个唯一的标识一样,一个载入JVM的类也有一个唯一的标识. 同理,载入JVM的类也有一个唯一的标识,在java中,一个类用其全限定类名(包括包名和类名)作为标识.但在JVM中,一个类用其全限定类名和其类加载器作为其唯一的标识.因此,如果在pg包中,有一个名为Person的类,被类

【深入理解JVM】类加载器与双亲委派模型

原文链接:http://blog.csdn.net/u011080472/article/details/51332866,http://www.cnblogs.com/lanxuezaipiao/p/4138511.html 加载类的开放性 类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因.在类加载的第一阶段"加载"过程中,需要通过一个类的全限定名来获取定义此类的二进制字节流,完成这个动作的代码块就是类加载器.这一动作是放在Java虚拟机外部

(转)JVM——自定义类加载器

背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上的大部分自定义类加载器文章,几乎都是贴一段实现代码,然后分析一两句自定义ClassLoader的原理.但是我觉得首先得把为什么需要自定义加载器这个问题搞清楚,因为如果不明白它的作用的情况下,还要去学习它显然是很让人困惑的. 首先介绍自定义类的应用场景: (1)加密:Java代码可以轻易的被反编译,如

jvm的类加载器,类装载过程

混沌初开,在一片名为jvm的世界中,到处都是一片虚无,直到一个名为BootstrapClassLoader的巨人劈开了世界,据说它是由名叫C++的女神所造,它从一个叫做jre/lib的宝袋中拿出一把开天之斧ExtensionClassLoader,以及其他各种各样五颜六色的宝物,这些宝物撒落在混沌世界中,化作了山山水水.紧接着,巨人又使用ExtensionClassLoader这把巨斧劈开了一个叫做jre/lib/ext的巨峰,那里瞬间迸发出了五颜六色的彩芒,彩芒四溅而去,让这个灰色的世界不再那

java jvm虚拟机类加载器

在Java中任意一个类都是由这个类本身和加载这个类的类加载器来确定这个类在JVM中的唯一性. 类加载器 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现, 以便让应用程序自己决定如何去获取所需要的类. 实现这个动作的代码模块称为“类加载器”. 类与类加载器 类加载器虽然只用于实现类的加载动作, 但它在Java程序中起到的作用却远远不限于类加载阶段. 对于任意一个类, 都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟

JVM之类加载器【转】

本文介绍了Java虚拟机(Java SE 11版本)加载类和接口. 加载类和接口 加载是指查找具有特定名称的类或接口类型的二进制形式的过程.典型的做法是,查找事先由Java编译器从源代码计算而来二进制表示,但也可能是通过动态计算. 二进制形式最终会构造成一个Class对象. 加载的精确语义在Java Java Machine Specification,Java SE 11 Edition的第5章中给出.在这里,我们从Java编程语言的角度概述了该过程. 类或接口的二进制格式通常是上面引用的Ja