java8类加载器示例&类加载1.8和1.8+的区别

示例代码

package com.example.demo;

public class ClassLoaderExample {
    public static void main(String[] args) {
        // 1.8及以下ClassLoaderExample sun.misc.Launcher$AppClassLoader@18b4aac2
        // 1.9+ ClassLoaderExample jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
        System.out.println("ClassLoaderExample " + ClassLoaderExample.class.getClassLoader());

        // 1.8及以下:ClassLoaderExample getParent sun.misc.Launcher$ExtClassLoader@4c873330
        // jdk9+ ClassLoaderExample getParent jdk.internal.loader.ClassLoaders$PlatformClassLoader@26a1ab54
        System.out.println("ClassLoaderExample getParent " + ClassLoaderExample.class.getClassLoader().getParent());

        // 1.8及以下 ClassLoaderExample getParent null 
        // jdk9+  ClassLoaderExample getParent getParent null
        System.out.println("ClassLoaderExample getParent getParent " + ClassLoaderExample.class.getClassLoader().getParent().getParent());

        // 1.8及以下 null
        // jdk9+ null
        System.out.println("String " + String.class.getClassLoader());

        // 1.8及以下 Exception in thread "main" java.lang.NullPointerException
        // jdk9+ Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.ClassLoader.getParent()" because the return value of "java.lang.Class.getClassLoader()" is null     at 
        // com.example.demo.ClassLoaderExample.main(ClassLoaderExample.java:18)
        System.out.println("String getParent " + String.class.getClassLoader().getParent());
    }
}

🌳 类加载器(ClassLoader)结构回顾

Java 的类加载器是分层级的,主要有三种类加载器(JDK 8 及以前):

  1. Bootstrap ClassLoader(引导类加载器)
    • 加载 Java 核心类库,如 java.lang.*
    • 用 C++ 编写,是 JVM 内部的一部分。
    • 不是 Java 对象(即不是 ClassLoader 的子类实例),因此在 Java 层获取不到它的引用(表现为 null)。
  2. Extension ClassLoader(扩展类加载器)
    • 加载 jre/lib/ext/ 目录下的类。
    • 是 Java 编写的,sun.misc.Launcher$ExtClassLoader 实例。
  3. Application ClassLoader(应用类加载器)
    • 加载应用程序 classpath 下的类。
    • 也是 Java 编写的,sun.misc.Launcher$AppClassLoader 实例。

代码运行时打印信息解释

System.out.println("ClassLoaderExample " + ClassLoaderExample.class.getClassLoader());

输出类似于:

ClassLoaderExample sun.misc.Launcher$AppClassLoader@18b4aac2

说明当前类是由应用类加载器加载的。


System.out.println("ClassLoaderExample getParent " + ClassLoaderExample.class.getClassLoader().getParent());

输出:

ClassLoaderExample getParent sun.misc.Launcher$ExtClassLoader@4c873330

AppClassLoader 的父类是 ExtClassLoader,正确无误。


System.out.println("ClassLoaderExample getParent getParent " + ClassLoaderExample.class.getClassLoader().getParent().getParent());

输出:

ClassLoaderExample getParent getParent null

✅ 解释:为什么最后是 null

  • ExtClassLoader 的父类是 Bootstrap ClassLoader
  • 但是 Bootstrap ClassLoader 是 JVM 内部实现,不是一个 Java 对象
  • 在 Java 层调用 getParent() 时,如果父加载器是 Bootstrap,就会返回 null

👉 换句话说:

ExtClassLoader.getParent() = BootstrapClassLoader → null in Java

所以你看到的是:

AppClassLoader.getParent()           = ExtClassLoader
ExtClassLoader.getParent()          = BootstrapClassLoader → null

✅ 小结

类加载器 类名 getParent() 的结果
应用类加载器 sun.misc.Launcher$AppClassLoader 返回 ExtClassLoader
扩展类加载器 sun.misc.Launcher$ExtClassLoader 返回 null(实际是 Bootstrap)
引导类加载器 JVM 内部实现(非 Java 对象) 无法用 Java 代码直接引用,getParent 为 null

好的,我们来系统性、严谨地讲解一下 Java 9 模块系统(Project Jigsaw) 引入之后,类加载器机制的变化 —— 特别是与模块(module)系统结合之后的差异。


🔧 Java 9 模块系统与类加载器关系变更详解

一、背景:Project Jigsaw(Java 9 引入)

Java 9 引入了 模块系统(Module System),目的是:

  • 增强封装性和可维护性。
  • 将 JDK 自身模块化(比如 java.base, java.sql, java.xml 等)。
  • 支持用户定义模块(module-info.java)。

二、Java 9 之前的类加载器结构(复习)

我们回顾下 JDK 8 及以前的类加载器结构:

BootstrapClassLoader  (C++实现,加载核心类库)
        ↑
ExtClassLoader        (Java实现,加载jre/lib/ext下类库)
        ↑
AppClassLoader        (Java实现,加载classpath中的类)

三、Java 9 之后:类加载器结构变化

主要变化:

  1. 引入了 Platform ClassLoader(新的中间层)。
  2. 扩展类加载器 ExtClassLoader 被废弃。
  3. 新的加载器层级结构如下:
BootstrapClassLoader      -> 加载 java.base 等核心模块
        ↑
PlatformClassLoader       -> 加载 JDK 提供的其他模块(例如 java.sql)
        ↑
AppClassLoader            -> 加载用户模块(即 classpath 或 modulepath 中的应用模块)

📌 说明:

  • PlatformClassLoader 替代了原来的 ExtClassLoader
  • 它加载的是 JDK 提供的标准模块,而不是 jre/lib/ext 目录(该目录从 Java 9 开始被废弃)。

四、PlatformClassLoader 特点

你可以通过以下方式访问:

ClassLoader platformClassLoader = ClassLoader.getPlatformClassLoader();

并通过查看其层级:

System.out.println("PlatformClassLoader: " + platformClassLoader);
System.out.println("PlatformClassLoader parent: " + platformClassLoader.getParent());

它的父类仍然是 BootstrapClassLoader(Java 中表现为 null)。


五、类与类加载器的关系在模块系统中的影响

模块系统不仅组织代码包,还与类加载器紧密相关:

模块位置 类加载器
java.base 等核心模块 BootstrapClassLoader
java.sql 等平台模块 PlatformClassLoader
用户定义模块 AppClassLoader

举个例子:

System.out.println("String.class loader: " + String.class.getClassLoader()); // null(Bootstrap)
System.out.println("java.sql.Driver.class loader: " + java.sql.Driver.class.getClassLoader()); // PlatformClassLoader
System.out.println("你自己的类 loader: " + YourClass.class.getClassLoader()); // AppClassLoader

六、模块系统对反射和访问权限的限制

Java 9 引入模块系统后,对于 setAccessible(true) 等反射操作增加了限制,默认情况下不能访问其它模块中未开放的 package

你需要:

  • 在命令行中添加 --add-opens 参数;
  • 或在模块描述符中添加 opensexports

✅ 总结

Java 版本 类加载器结构变化说明
Java 8及以前 Bootstrap → Ext → App
Java 9及以后 Bootstrap → Platform → App(Ext废弃)

主要新增:

  • PlatformClassLoader:加载平台模块,替代原 ExtClassLoader
  • 模块系统与类加载器绑定更紧密,强调包封装与访问控制。

posted @ 2025-04-19 18:24  BigOrang  阅读(55)  评论(0)    收藏  举报