java怎么加载_java文件是如何加载到jvm

内存结构

9dfd5760fc0825388ad1c0504aa2e9dd.png

加载流程

f2a75622b02274ff97d50031a63ee64b.png

加载:

查找字节流,并且据此创建类的过程。

jvm中默认存在boostrapClassLoader

boostrapClassLoader  -->  lib 目录下 jar 包中的类(以及由虚拟机参数 -Xbootclasspath 指定的类

ExtClassloader  -->  JRE 的 lib/ext 目录下 jar 包中的类(以及由系统变量 java.ext.dirs 指定的类

ApplicationClassLoader   -->   -cp/-classpath、系统变量 java.class.path 或环境变量 CLASSPATH 所指定的路径

类加载器的双亲委托机制

1. 当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。

每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。

2. 当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到bootstrp ClassLoader.

3. 当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。

代码:ClassLoader#loadClass

{

synchronized (getClassLoadingLock(name)) {

// First, check if the class has already been loaded

Class> c = findLoadedClass(name);

if (c == null) {

long t0 = System.nanoTime();

try {

if (parent != null) {

c = parent.loadClass(name, false);

} else {

c = findBootstrapClassOrNull(name);

}

} catch (ClassNotFoundException e) {

// ClassNotFoundException thrown if class not found

// from the non-null parent class loader

}

if (c == null) {

// If still not found, then invoke findClass in order

// to find the class.

long t1 = System.nanoTime();

c = findClass(name);

// this is the defining class loader; record the stats

sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);

sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);

sun.misc.PerfCounter.getFindClasses().increment();

}

}

if (resolve) {

resolveClass(c);

}

return c;

}

}

复制代码

关键步骤

if (parent != null) {

c = parent.loadClass(name, false);

}

复制代码

当parent不为空优先从父类加载器加载类。

场景:如果应用中恶意实现java中的基础类,比如String。如果加载了这个恶意的类,后面有String创建的对象、调用String中的方法都会存在问题,由于双亲委托机制存在不会加载都应用中的恶意类。

(某些情况下也可以破坏双亲委托机制,这里不细讲。感兴趣的百度and谷歌)

链接:

链接,是指将创建成的类合并至 Java 虚拟机中,使之能够执行的过程。

1、验证阶段:确保被加载类能够满足 Java 虚拟机的约束条件

2、准备阶段:为加载的类中静态字段分配内存,以及为依赖的类添加符号引用(能够无歧义地定义到具体目标)。

3、解析阶段:将符号引用解析成为实际引用。如果符号引用指向一个未被加载 的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载(但未必触发这个类的 链接以及初始化。)

初始化

标记为常量值的字段赋值,以及执行 < clinit > 类构造器方法的过程。

初始化静态变量语句。

以上就是demo.java加载到jvm的完整过程。

------------------------------------------------------------------------------------------------

扩展:

类主动初始化时机:

1. 当虚拟机启动时,初始化用户指定的主类;

2. 当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;

3. 当遇到调用静态方法的指令时,初始化该静态方法所在的类;

4. 当遇到访问静态字段的指令时,初始化该静态字段所在的类;

5. 子类的初始化会触发父类的初始化;

6. 如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化, 会触发该接口的初始化;

7. 使用反射 API 对某个类进行反射调用时,初始化这个类;

8. 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值