-
2022-02-16 11:34:42
Java类加载需要经历7个过程:
1.加载
加载是类加载的第一个过程,在这个阶段,将完成以下三件事情:
- 通过一个类的全限定名获取该类的二进制流。
- 将该二进制流中的静态存储结构转化为方法去运行时数据结构。
- 在内存中生成该类的Class对象,作为该类的数据访问入口。
2.验证
验证目的是为了确保Class文件的字节流中的信息不会危害到虚拟机,在该阶段主要完成以下四种验证:
- 文件格式验证:验证字节流是否符合Class文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型。
- 元数据验证:对字节码描述的信息进行语义分析,如这个类中是否有父类,是否集成了不被继承的类等。
- 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等。
- 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。
3.准备
准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在Java堆中。
public static int value=123;//在准备阶段value初始值为0,初始化阶段才变为123。
4.解析
该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。
5.初始化
初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。
6.使用
7.卸载
更多相关内容 -
类加载过程
2022-02-20 22:11:511. JVM类加载过程 加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的 2.类加载方式 : 导入class文件 2.1隐式加载 2.2显式加载 3. 验证:确保被加载的类的正确性 4. 准备:为类的静态变量分配内存,并将...1. JVM类加载过程
加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的2.类加载方式 : 导入class文件
2.1隐式加载
2.2显式加载
3. 验证:确保被加载的类的正确性4. 准备:为类的静态变量分配内存,并将其赋默认值
定义静态变量时指定初始值。如 private static String x="123";
在静态代码块里为静态变量赋值。如 static{ x="123"; }
(5)解析 :
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址;
解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。
5. 初始化:对静态变量和静态代码块执行初始化工作。什么时候会触发初始化?
1.遇到new,getstatic,putstatic,invokestatic这4条指令;2.使用java.lang.reflect包的方法对类进行反射调用;
3.初始化一个类的时候,如果发现其父类没有进行过初始化,则先初始化其父类(注意!如果其父类是接口的话,则不要求初始化父类);
4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main方法的那个类),虚拟机会先初始化这个主类;
以下情况不会触发类的初始化:
1.同类子类引用父类的静态字段,不会导致子类初始化。至于是否会触发子类的加载和验证,取决于虚拟机的具体实现;
2.通过数组定义来引用类,也不会触发类的初始化;例如:People[] ps = new People[100];
3.引用一个类的常量也不会触发类的初始化6. 卸载阶段
执行了System.exit()方法。
程序正常执行结束。
程序在执行过程中遇到了异常或错误而异常终止。
由于操作系统出现错误而导致Java虚拟机进程终止。Spring单例Bean与单例模式的区别在于他们关联的环境不一样,单例模式是指在一个jvm进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。与此相比,Spring的单例Bean是与其容器(ApplicationContext)密切相关的,所以在一个JVM进程中,如果有多个Spring容器,即使是单例bean,也一定会创建多个实例。
单例bean的优点:
1.spring通过反射创建bean消耗资源、并且在对多个bean进行分配的时候消耗资源
2.减少bean的垃圾回收
3.除了第一次创建以外后面都是从缓存中获取bean,速度很快
创建bean的过程:
实例化 ----> 属性填充 ---> 初始化--->AOP ---> 代理对象--->bean
Spring注解@component、@service、@Autowired等作用与区别
1、@Service用于标注业务层组件
2、@Controller用于标注控制层组件(如struts中的action)
3、@Repository用于标注数据访问组件,即DAO组件.
4、@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
5、@Autowired与@Resource的区别
@Autowired由Spring提供,只按照byType注入,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为false。如果想使用名称装配可以结合@Qualifier注解进行使用。
@Resource由J2EE提供,默认按照byName自动注入,Spring将@Resource注解的name属性解析为bean的名字,type属性则解析为bean的类型
<bean id="userServiceImpl" class="cn.com.bochy.service.impl.UserServiceImpl">
byName就是通过Bean的id或者name,byType就是按Bean的Class的类型
linux常用指令:
- chown (change owner) : 修改所属用户与组。
- chmod (change mode) : 修改用户的权限。
-
Linux 磁盘管理常用三个命令为 df、du 和 fdisk。
- df(英文全称:disk free):列出文件系统的整体磁盘使用量 df -h
- du(英文全称:disk used):检查磁盘空间使用量
- fdisk:用于磁盘分区
SPI,Service Provider Interface,一种服务发现机制
-
JVM类加载过程
2019-06-20 15:10:251. JVM类加载过程 1.概述 从类的生命周期而言,一个类包括如下阶段: 加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序进行,而解析阶段则不一定,它在某些情况下...1. JVM类加载过程
1.概述
从类的生命周期而言,一个类包括如下阶段:
加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序进行,而解析阶段则不一定,它在某些情况下可能在初始化阶段后在开始,因为java支持运行时绑定。
2. 类加载时机
加载(loading)阶段,java虚拟机规范中没有进行约束,但初始化阶段,java虚拟机严格规定了有且只有如下5种情况必须立即进行初始化(初始化前,必须经过加载、验证、准备阶段):
(1)使用new实例化对象时,读取和设置类的静态变量、静态非字面值常量(静态字面值常量除外)时,调用静态方法时。
(2)对内进行反射调用时。
(3)当初始化一个类时,如果父类没有进行初始化,需要先初始化父类。
(4)启动程序所使用的main方法所在类
(5)当使用1.7的动态语音支持时。
如上5种场景又被称为主动引用,除此之外的引用称为被动引用,被动引用有如下3种常见情况
- 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
- 定义对象数组和集合,不会触发该类的初始化
- 类A引用类B的static final常量不会导致类B初始化(注意静态常量必须是字面值常量,否则还是会触发B的初始化)
public class TestClass { public static void main(String[] args) { System.out.println(ClassInit.str); System.out.println(ClassInit.id); } } class ClassInit{ public static final long id=IdGenerator.getIdWorker().nextId();//需要初始化ClassInit类 public static final String str="abc";//字面值常量 static{ System.out.println("ClassInit init"); } }
- 通过类名获取Class对象,不会触发类的初始化。如System.out.println(Person.class);
- 通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初始化。
- 通过ClassLoader默认的loadClass方法,也不会触发初始化动作
注意:被动引用不会导致类初始化,但不代表类不会经历加载、验证、准备阶段。
3. 类加载方式
这里的类加载不是指类加载阶段,而是指整个类加载过程,即类加载阶段到初始化完成。
(1)隐式加载
- 创建类对象
- 使用类的静态域
- 创建子类对象
- 使用子类的静态域
- 在JVM启动时,BootStrapLoader会加载一些JVM自身运行所需的class
- 在JVM启动时,ExtClassLoader会加载指定目录下一些特殊的class
- 在JVM启动时,AppClassLoader会加载classpath路径下的class,以及main函数所在的类的class文件
(2)显式加载
- ClassLoader.loadClass(className),只加载和连接、不会进行初始化
- Class.forName(String name, boolean initialize,ClassLoader loader); 使用loader进行加载和连接,根据参数initialize决定是否初始化。
2. 加载阶段
加载是类加载过程中的一个阶段,不要将这2个概念混淆了。
在加载阶段,虚拟机需要完成以下3件事情:
- 通过一个类的全限定名来获取定义此类的二进制字节流
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
加载.class文件的方式
- 从本地系统中直接加载
- 通过网络下载.class文件
- 从zip,jar等归档文件中加载.class文件
- 从专有数据库中提取.class文件
- 将Java源文件动态编译为.class文件
相对于类生命周期的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既可以使用系统提供的类加载器来完成加载,也可以自定义自己的类加载器来完成加载。
3. 连接阶段
3.1 验证:确保被加载的类的正确性
确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
- 文件格式验证:验证字节流是否符合Class文件格式的规范,如:是否以模数0xCAFEBABE开头、主次版本号是否在当前虚拟机处理范围内等等。
- 元数据验证:对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求;如:这个类是否有父类,是否实现了父类的抽象方法,是否重写了父类的final方法,是否继承了被final修饰的类等等。
- 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的,如:操作数栈的数据类型与指令代码序列能配合工作,保证方法中的类型转换有效等等。
- 符号引用验证:确保解析动作能正确执行;如:通过符合引用能找到对应的类和方法,符号引用中类、属性、方法的访问性是否能被当前类访问等等。
验证阶段是非常重要的,但不是必须的。可以采用-Xverify:none参数来关闭大部分的类验证措施。
3.2 准备:为类的静态变量分配内存,并将其赋默认值
为类变量分配内存并设置类变量初始值,这些内存都将在方法区中分配。对于该阶段有以下几点需要注意:
- 只对static修饰的静态变量进行内存分配、赋默认值(如0、0L、null、false等)。
- 对final的静态字面值常量直接赋初值(赋初值不是赋默认值,如果不是字面值静态常量,那么会和静态变量一样赋默认值)。
3.3 解析:将常量池中的符号引用替换为直接引用(内存地址)的过程
符号引用就是一组符号来描述目标,可以是任何字面量。属于编译原理方面的概念如:包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。
直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。如指向方法区某个类的一个指针。
假设:一个类有一个静态变量,该静态变量是一个自定义的类型,那么经过解析后,该静态变量将是一个指针,指向该类在方法区的内存地址。 具体见后续文章。
4. 初始化:为类的静态变量赋初值
赋初值两种方式:
- 定义静态变量时指定初始值。如 private static String x="123";
- 在静态代码块里为静态变量赋值。如 static{ x="123"; }
注意:只有对类的主动使用才会导致类的初始化。
5. clinit 与 init
在编译生成class文件时,编译器会产生两个方法加于class文件中,一个是类的初始化方法clinit, 另一个是实例的初始化方法init。
5.1 clinit
clinit指的是类构造器,主要作用是在类加载过程中的初始化阶段进行执行,执行内容包括静态变量初始化和静态块的执行。
注意事项:
1. 如果类中没有静态变量或静态代码块,那么clinit方法将不会被生成。
2. 在执行clinit方法时,必须先执行父类的clinit方法。
3. clinit方法只执行一次。
3. static变量的赋值操作和静态代码块的合并顺序由源文件中出现的顺序决定。如下代码所示:
public class TestClass { public static void main(String[] args) { ClassInit init=ClassInit.newInstance(); System.out.println(init.x); System.out.println(init.y); } } class ClassInit{ private static ClassInit init=new ClassInit(); public static int x; public static int y=0; static{ x=10; y=10; } private ClassInit(){ x++; y++; } public static ClassInit newInstance(){ return init; } } //在类加载到连接完成阶段,ClassInit类在内存中的状态为:init=null,x=0,y=0 //初始化阶段时,需要执行clinit方法,该方法类似如下伪代码: clinit(){ //init=new ClassInit();调用构造方法 x++;//x=1 因为此时x的值为连接的准备阶段赋的默认值0,然后++变成1 y++;//y=1 因为此时y的值为连接的准备阶段赋的默认值0,然后++变成1 //x=0;//为什么这里没有执行x=0,因为程序没有给x赋初值,因此在初始化阶段时,不会执行赋初值操作 y=0;//因为类变量y在定义时,指定了初值,尽管初值为0,因此在初始化阶段的时候,需要执行赋初值操作 x++;//第一个静态块的自增操作,结果为x=2; y++;//第一个静态块的自增操作,结果为y=1; } //所以最终结果为x=2,y=1 //如果private static ClassInit init=new ClassInit(); 代码在public static int y=0;后面,那么clinit方法的伪代码如下: clinit(){ //x=0;//这里虽然没有执行,但此时x的值为连接的准备阶段赋的默认值0 y=0;//因为类变量y在定义时,指定了初值,尽管初值为0,因此在初始化阶段的时候,需要执行赋初值操作 //init=new ClassInit();调用构造方法 x++;//x=1 因为此时x的值为连接的准备阶段赋的默认值0,然后++变成1 y++;//y=1 因为此时y的值为初始化阶段赋的初值,只是这个初值刚好等于默认值0而已,然后++变成1 x++;//第一个静态块的自增操作,结果为x=2; y++;//第一个静态块的自增操作,结果为y=2; } //最终结果为x=2,y=2
5.2 init
init指的是实例构造器,主要作用是在类实例化过程中执行,执行内容包括成员变量初始化和代码块的执行。
注意事项:
1. 如果类中没有成员变量和代码块,那么clinit方法将不会被生成。
2. 在执行init方法时,必须先执行父类的init方法。
3. init方法每实例化一次就会执行一次。
3. init方法先为实例变量分配内存空间,再执行赋默认值,然后根据源码中的顺序执行赋初值或代码块。如下代码所示:
public class TestClass { public static void main(String[] args) { ClassInit init=new ClassInit(); } } class ClassInit{ public int x; public int y=111; public ClassInit(){ x=1; y=1; } { x=2; y=2; } { x=3; y=3; } } //实例化步骤为:先为属性分配空间,再执行赋默认值,然后按照顺序执行代码块或赋初始值,最后执行构造方法 //根据上述代码,init方法的伪代码如下: init(){ x=0;//赋默认值 y=0;//赋默认值 y=111;//赋初值 x=2;//从上到下执行第一个代码块 y=2;//从上到下执行第一个代码块 x=3;//从上到下执行第二个代码块 y=3;//从上到下执行第二个代码块 //ClassInit();执行构造方法 x=1;//最后执行构造方法 y=1;//最后执行构造方法 } //如果上述代码的成员变量x,y的定义在类最后时,那么init方法的伪代码如下: init(){ x=0;//赋默认值 y=0;//赋默认值 x=2;//从上到下执行第一个代码块 y=2;//从上到下执行第一个代码块 x=3;//从上到下执行第二个代码块 y=3;//从上到下执行第二个代码块 y=111;//赋初值 //ClassInit();执行构造方法 x=1;//最后执行构造方法 y=1;//最后执行构造方法 }
6. 卸载阶段
执行了System.exit()方法
程序正常执行结束
程序在执行过程中遇到了异常或错误而异常终止
由于操作系统出现错误而导致Java虚拟机进程终止
-
(一) 类加载过程详解 (类加载机制 第一篇)
2021-11-04 14:46:24当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到 JVM。 package com.shendu; public class JvmTest01 { public static final int initData = 666; public int compute() { ...当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到 JVM。
package com.shendu; public class JvmTest01 { public static final int initData = 666; public int compute() { int a = 1; int b = 2; int c = (a + b) * 10; return c; } public static void main(String[] args) { new JvmTest01().compute(); } }
如上面的代码:当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到 JVM。
通过Java命令执行代码的大体流程如下:
以上就是整个从jvm到java中main程序的执行全部过程,main是所有程序的入口。
整个类加载如图所示
加载
加载,是指Java虚拟机查找字节流(查找.class文件),并且根据字节流创建java.lang.Class对象的过程。这个过程,将类的.class文件中的二进制数据读入内存,放在运行时区域的方法区内。然后在堆中创建java.lang.Class对象,用来封装类在方法区的数据结构。
类加载阶段:
(1)Java虚拟机将.class文件读入内存,并为之创建一个Class对象。
(2)任何类被使用时系统都会为其创建一个且仅有一个Class对象。
(3)这个Class对象描述了这个类创建出来的对象的所有信息,比如有哪些构造方法,都有哪些成员方法,都有哪些成员变量等。
验证
验证阶段作用是保证Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害。如果验证失败,就会抛出一个java.lang.VerifyError异常或其子类异常。验证过程分为四个阶段:文件格式验证:验证字节流文件是否符合Class文件格式的规范,并且能被当前虚拟机正确的处理。
元数据验证:是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范要求
字节码验证:主要是进行数据流和控制流的分析,保证被校验类的方法在运行时不会危害虚拟机。
符号引用验证:符号引用验证发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在解析阶段中发生。
准备
准备阶段为变量分配内存并设置类变量的初始化。在这个阶段分配的仅为类的变量(static修饰的变量),而不包括类的实例变量。对已非final的变量,JVM会将其设置成“零值”,而不是其赋值语句的值:pirvate static int size = 12;。那么在这个阶段,size的值为0,而不是12。但final修饰的类变量将会赋值成真实的值。解析
解析过程是将常量池内的符号引用替换成直接引用。主要包括四种类型引用的解析。类或接口的解析、字段解析、方法解析、接口方法解析。初始化
初始化,则是为标记为常量值的字段赋值的过程。换句话说,只对static修饰的变量或语句块进行初始化。
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
类加载器和双亲委派机制
上面的类加载过程主要是通过类加载器来实现的,Java里有如下几种类加载器
- 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如 rt.jar、charsets.jar等
- 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR 类包
- 应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载你自己写的那 些类 自定义加载器:负责加载用户自定义路径下的类包
双亲委派机制
一个类只有被第一次主动使用时,才会被java虚拟机加载
主动使用的情况(6种)
1、创建类的实例
2、访问类的静态变量
3、调用类的静态方法
4、反射加载
5、初始化一个类的子类
6、java虚拟机启动时被标记为启动类的类定义了几个类加载器。
-
AppClassLoader 系统类加载器 负责的目录如下:
- %JAVA_HOME%/jre/lib
- -Xbootclasspath 参数指定的目录
- 系统属性sun.boot.class.path
-
ExtClassLoader 扩展类加载器 负责的目录如下:
- %JAVA_HOME%/jre/lib/ext
- 系统属性java.ext.dirs指定的类库
-
Bootstrap classLoader 启动类加载器 负责的目录如下:
- 环境变量 classpath
- -cp
- 系统属性java.class.path
各个加载器的加载路径的验证
AppClassLoader 加载路径地址
String appProperty = System.getProperty("java.class.path"); for (String s : appProperty.split(";")) { System.out.println(s); }
打印为:
C:\Program Files\Java\jdk1.8.0_281\jre\lib\charsets.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\deploy.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\access-bridge-64.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\cldrdata.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\dnsns.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\jaccess.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\jfxrt.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\localedata.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\nashorn.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunec.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunjce_provider.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunmscapi.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunpkcs11.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\zipfs.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\javaws.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\jce.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\jfr.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\jfxswt.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\jsse.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\management-agent.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\plugin.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\resources.jar C:\Program Files\Java\jdk1.8.0_281\jre\lib\rt.jar D:\tcl_ouyang\demo_coding\jvmclassload\target\classes D:\tcl_ouyang\dev_soft\IntelliJ IDEA 2019.1.4\lib\idea_rt.jar
虽然打印了这么多的路径,但是其他的jar已经被它的父加载器给加载过了,根据双亲委托机制,其实AppClassLoader只是加载项目中的classpath路径下的类。
ExtClassLoader 加载路径
String extDirs = System.getProperty("java.ext.dirs"); for (String path : extDirs.split(";")) { System.out.println(path); }
打印
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext C:\Windows\Sun\Java\lib\ext
Bootstrap classLoader加载路径
URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs(); for (URL url : urLs) { System.out.println(url.toExternalForm()); }
打印
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/resources.jar file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/rt.jar file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/sunrsasign.jar file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/jsse.jar file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/jce.jar file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/charsets.jar file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/jfr.jar file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/classes
我们在来验证下,各个加载器之间的关系
System.out.println(JvmTest02.class.getClassLoader()); System.out.println(JvmTest02.class.getClassLoader().getParent()); System.out.println(JvmTest02.class.getClassLoader().getParent().getParent());
打印:
sun.misc.Launcher$AppClassLoader@18b4aac2 sun.misc.Launcher$ExtClassLoader@1b6d3586 null
我们可以得出一个结论:AppClassLoader的父加载器是ExtClassLoader,然后我们的引导类加载器是不对外开放的,因为它是C++编写的,它不是一个类
JVM类加载器是有亲子层级结构的,如下图
这里类加载其实就有一个双亲委派机制,加载某个类时会先委托父加载器寻找目标类,找不到再 委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的 类加载路径中查找并载入目标类。 比如我们的Math类,最先会找应用程序类加载器加载,应用程序类加载器会先委托扩展类加载 器加载,扩展类加载器再委托引导类加载器,顶层引导类加载器在自己的类加载路径里找了半天 没找到Math类,则向下退回加载Math类的请求,扩展类加载器收到回复就自己加载,在自己的 类加载路径里找了半天也没找到Math类,又向下退回Math类的加载请求给应用程序类加载器, 应用程序类加载器于是在自己的类加载路径里找Math类,结果找到了就自己加载了。。 双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载
为什么要设计双亲委派机制?
-
沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心 API库被随意篡改 避免类的重复加载:
-
当父亲已经加载了该类时,就没有必要子ClassLoader再加载一 次,保证被加载类的唯一性
-
JVM的类加载过程以及双亲委派模型详解
2020-08-25 22:01:41主要介绍了JVM的类加载过程以及双亲委派模型详解,类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象。,需要的朋友可以参考下 -
Java类加载过程梳理,一篇搞定
2022-06-05 00:13:38来自:blog.csdn.net/hsz2568952354/article/details/96763284最近在看Java虚拟机,正好看到类加载这块,所以简单记录下所学到的知识,作为笔记。首先,我们编写好的Java代码,经过编译变成.class文件,然后类加载器... -
JVM-01 类加载过程及源码分析
2021-08-14 22:02:03一、类加载过程分析 我们通过ide写的java代码,毫无疑问是最终需要加载到JVM来运行的。试想JVM作为跨语言的平台,能同时支持多种编程语言(js、groory、scala…等)的字节码文件运行,那么在字节码文件和JVM之间,... -
简述Java的类加载过程
2021-09-10 00:07:41Java类加载需要经历一下几个过程: 1)加载 加载时类加载的第一个过程,在这个阶段,将完成一下三件事情: a.通过一个类的全限定名获取该类的二进制流。 b.将该二进制流中的静态存储结构转化为方法去运行时数据结构。... -
浅析 Tomcat类加载过程
2019-07-28 02:38:30java 类加载器的功能是将 class 加载入内存, tomcat的的应用程序加载过程使 tomcat拥有了在同一个 jvm 中加载管理多个应用的功能. 在介绍 tomcat应用程序加载过程前,我们先简单了解下 java 类加载机制.在Class 类中,... -
简述类加载过程详解
2022-02-15 23:17:06简述JVM类加载过程详解 -
Java的类加载过程
2021-02-11 00:13:36而我们所说的类加载过程即是指JVM虚拟机把.class文件中类信息加载进内存,并进行解析生成对应的class对象的过程。 举个通俗点的例子来说,JVM在执行某段代码时,遇到了class A, 然而此时内存中并没有class A的相关... -
JVM类加载的基本流程
2022-05-23 17:31:22JVM 的基本流程 -
简述类加载过程
2020-02-29 14:01:533. 类加载的总体流程3.1 加载过程3.2 验证过程3.3 准备过程3.4 解析过程3.5 初始化过程 < hr/> 1. 什么是类加载 1.1 类加载的五大步骤 2. 什么时候触发类加载? 3. 类加载的总体流程 3.1 加载过程 3.2 验证... -
类加载的过程
2022-04-16 14:25:03文章目录1....类加载过程的第一步,主要完成下面这三件事情: ①. 通过全类名获取定义此类的二进制字节流 ②.将字节流所代表的静态存储结构转换为方法区运行时数据结构 ③.在内存中生成一个代表该类的 Class -
JVM(三):类加载机制(类加载过程和类加载器)1
2022-08-03 19:02:541.编写个向接的应程序,可能等到运时再指定其实现的类 2.户可以定义个类加载器,让程序在运时从络或其他地加载 1.加载:(重点) 1.通过“类全名”来获取定义此 -
2. Class类加载过程
2022-03-09 14:42:24Class类加载过程 类加载器子系统 类加载器子系统只负责加载class文件,class文件的文件头有文件标识。 ClassLoader只负责class的加载,至于是否可以运行,由Execution Engine(执行引起)决定。 加载类的信息存放... -
JVM系列(一):JVM类加载过程详解
2021-12-17 18:11:08Java 通过引入字节码和 JVM 机制,提供了强大的跨平台能力,理解 Java 的类加载机制是深入 Java 开发的必要条件。 -
深入理解Java虚拟机——类加载过程
2022-03-20 21:18:06目录一、类加载过程的概述二、类加载的加载源 一、类加载过程的概述 “加载”是“类加载”(Class Loading)过程的一个阶段,在加载阶段,虚拟机需要完成以下3件事情: (1)、通过一各类的全限定名来获取定义此类的... -
浅谈 Java 的类加载过程
2022-02-12 09:24:08一般来说,我们把 Java 的类加载过程分为三个主要步骤:加载,连接,初始化,具体行为在 Java 虚拟机规范里有非常详细的定义。 首先是加载过程(Loading),它是 Java 将字节码数据从不同的数据源读取到 JVM 中,并... -
Java类加载过程图解
2018-08-22 16:52:36为什么用.class的方式加载类和以Class.forName()的方式加载的结果不同呢,原因很简单,就是类加载过程的不同。 这就扯到基础理解上了,就是Java是如何加载一个类的呢? 上图是我绘制的整个Java类加载过程。 ... -
基础巩固之图解类加载过程与双亲委派模型
2018-10-13 11:32:27类加载的时机 类从被加载到虚拟机中内存开始,到卸载除内存为止,它的生命周期包括如下图所示: 上图中的 加载,验证,准备,初始化,卸载这5个步骤的顺序是固定的,类的加载器也必须按这个顺序开始,而解析... -
类的加载过程
2022-03-01 14:39:14类的加载过程 类的加载过程整体可分为3个环节 加载->链接(验证,准备,解析)->初始化 加载(loading) 通过一个类的全限定类名获取定义此类的二进制字节流 将这个字节流所代表的静态存储结构转化为方法区的... -
Java 类的加载过程
2022-01-20 22:54:28Java 类的加载过程 当程序主动使用某个类时,如果该类还没有加载到内存中,则通过以下三个步骤对类进行加载初始化: 类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象到方法区中,此过程由类... -
再战JVM (1) 类加载过程
2021-04-05 12:30:07类加载过程一. 类加载过程二. 加载1. 加载过程2. 加载class文件的方式三. 连接1. 验证2. 准备3. 解析1. 类或接口的解析2. 字段的解析3. 方法解析 一. 类加载过程 类加载过程可以分为三个阶段 加载(Loading) 连接... -
JVM—类加载过程学习
2020-12-22 07:34:001 类加载过程图解 系统加载Class类型的文件主要是:加载->连接->初始化,其中连接分为:验证->准备->解析;其实,整个生命周期是7步,类从被加载到虚拟机内存中开始,到卸载出内存为止,分为:加载->验证->准备... -
Java类加载基本过程详细介绍
2020-08-31 23:19:51主要介绍了Java类加载基本过程详细介绍的相关资料,需要的朋友可以参考下 -
类加载的全过程
2022-05-31 23:33:04java虚拟机中类加载的全过程:“加载(Loading)”阶段是整个“类加载(Class Loading)”过程中的一个阶段,在加载阶段,java...例如:相对于类加载过程中的其他阶段,非数组类型的加载阶段(准确地说,是加载阶段中