跳转至

能否自定义类名为 java.lang.System / java.lang.String?

结论

不能。即使你写了一个 package java.lang; public class System {},也无法被正常加载,更无法覆盖 JDK 自带的类。根本原因是 类加载的双亲委派机制

为什么不行

1. 启动类加载器(Bootstrap ClassLoader)优先加载

java.lang.Systemjava.lang.String 这些核心类由 Bootstrap ClassLoader(C++ 实现,加载 $JAVA_HOME/jre/lib/rt.jar)加载。

当你的代码或自定义类加载器请求加载 java.lang.System 时,先委派给父加载器,最终委派到 Bootstrap,它已经加载了 JDK 自带的版本,直接返回,根本不会加载你写的那个类。

2. 即使绕过重载,也会被安全管理器拦截

JDK 6 以后,ClassLoader#defineClassjava. 开头的包名做了硬检查:

// ClassLoader#preDefineClass
if (name != null && name.startsWith("java.")) {
    throw new SecurityException(
        "Prohibited package name: " + name);
}

任何 java.* 包下的类,只允许 Bootstrap ClassLoader 定义。

验证

package java.lang;

public class System {
    public static void main(String[] args) {
        System.out.println("hello"); // 这里的 System 指哪个?
    }
}

直接运行会抛:

Exception in thread "main" java.lang.SecurityException:
Prohibited package name: java.lang

如果真的想"修改"核心类

只能用 BootClassPath 扩展-Xbootclasspath/p: 提前注入自己的版本(已废弃/高风险),或使用 Java Agent(Instrumentation)在运行时重定义类。但这些都是hack 手段,生产环境绝不可取。

安全含义

双亲委派 + java. 包名检查是 JVM 的安全基石,防止恶意代码冒充核心类窃取或篡改行为。面试中答出这一点会显著加分。