JAVA 类加载器

类加载器

 

在 java 中,类基于按需加载,所有的类都是使用类加载器进行加载,就是将 .class 文件加载到内存。JVM 中内置了三个类加载器,分别是:启动类加载器,扩展类加载器,应用类加载器。除了启动类加载器之外,其他的 JAVA 实现的类加载器都是继承 java.lang.ClassLoader。

  • 启动类加载器:最顶层的加载类,使用 C++ 实现。负责加载 %JAVA_HOME%/lib 目录下的 jar 包和类或者被 -Xbootclasspath 参数指定的路径中的所有类;
  • 扩展类加载器:主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包;
  • 应用类加载器:面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。

类加载器关系

每个类加载都有一个父类加载器,通过下面的程序来验证。

public class ClassLoaderDemo {
    public static void main(String[] args) {
        System.out.println("ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader());
        System.out.println("The Parent of ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader().getParent());
        System.out.println("The GrandParent of ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader().getParent().getParent());
    }
}
ClassLodarDemo's ClassLoader is sun.misc.Launcher$AppClassLoader@18b4aac2
The Parent of ClassLodarDemo's ClassLoader is sun.misc.Launcher$ExtClassLoader@1b6d3586
The GrandParent of ClassLodarDemo's ClassLoader is null

AppClassLoader 的父类加载器为 ExtClassLoader, ExtClassLoader的父类加载器为 null,null 并不代表 ExtClassLoader 没有父类加载器,而是 BootstrapClassLoader 。

双亲委派模型

虚拟机在加载类的时候,首先会判断该类是否被加载过,如果被加载过则直接返回,否则会尝试加载类。加载的时候会寻找父类加载器的 classLoad() 函数处理,因此所有的请求最终都会发送到顶层的启动类加载器中。当父类无法处理的时候才会交由自己处理。当父类加载器为 null 时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。这种机制称为双亲委派。委派的过程可以分为三个步骤:

  • 收到类加载的请求之后,类加载器不会加载类,将这个请求委派其父类加载器;
  • 如果父类加载器还存在父类加载器,则进一步向上委托,依次向上,最终会到达启动类加载器;
  • 如果父类加载器可以加载就完成加载任务成功返回,倘若不能加载,子类才尝试去加载。

例子说明机制

自行创建 java.lang 包,在其目录下创建 String 类,增加 main 函数执行。

package java.lang;

public class String {

  public static void main(String[] args) {
    System.out.println("hello world");
  }
}

出现了 在类 java.lang.String 中找不到 main 方法。

错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
   public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application

由于 String 类在 java.lang 包下,在申请加载 String 类时,加载类会请求其父类加载器加载,会直接请求启动类加载器,启动类加载器从 java.lang 中发现了 String 类,并将其加载返回。但是此 String 并非自定义的 String, 该类没有 main 入口,因此出现该异常。

双亲委派好处

双亲委派模型保证了 Java 程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值