文章内容收录到个人网站,方便阅读:hardyfish.top/
Java虚拟机规范.Java SE 8版:
- 资料链接:url81.ctfile.com/f/57345181-...
- 访问密码:3899
深入理解Java虚拟机:JVM高级特性与最佳实践(第3版):
- 资料链接:url81.ctfile.com/f/57345181-...
- 访问密码:3899
在 Java 中,即使破坏了 双亲委派模型 ,理论上依然无法完全重写 java.lang.String
类。
这是因为 JVM 对 String
类有特殊的限制和处理机制,具体如下:
原因分析
-
JVM 内置限制
java.lang.String
是 JVM 的核心类,其加载和使用受到严格限制。JVM 会优先加载和使用由引导类加载器(Bootstrap ClassLoader)加载的String
类。- 即使你破坏了双亲委派模型,定义了自己的
java.lang.String
类,JVM 在加载和运行中仍会优先使用引导类加载器加载的原生String
类。
-
类加载机制
- 引导类加载器加载的类是 JVM 的核心组件(如
java.lang
包下的类),例如java.lang.String
、java.lang.Object
等。 - 这些核心类无法被用户自定义的类加载器替换或重新加载,即使破坏双亲委派,
java.lang.String
依然会被优先加载,且不允许被覆盖。
- 引导类加载器加载的类是 JVM 的核心组件(如
-
安全性限制
- Java 标准库中
java.lang.String
的不可替换性是 JVM 保证平台安全性和一致性的基础。如果允许替换String
,可能会导致各种意料之外的安全问题。
- Java 标准库中
defineClass()
方法的限制
-
JVM 提供的
ClassLoader
的defineClass()
方法会对类的全限定名进行检查:- 如果类的全限定名以
java.
开头,则直接抛出SecurityException
,防止覆盖java
包下的核心类。
- 如果类的全限定名以
-
这项检查在 JVM 的底层实现中被硬编码,无法通过常规方式绕过。
尝试覆盖 java.lang.String
的结果
示例代码:假设你尝试自定义一个 java.lang.String
类:
Java
package java.lang;
public class String {
public String() {
System.out.println("My String");
}
}
编译结果
编译时会提示错误:
vbnet
error: cannot access java.lang.String
这是因为 Java 禁止用户在 java.lang
包下定义核心类。
绕过编译检查
使用某些工具或方法绕过编译检查(如直接修改 .class
文件),在运行时仍然会因为类加载机制而失败。
破坏双亲委派的场景
即使破坏双亲委派模型(如自定义类加载器,优先加载用户定义的类),由于 JVM 会始终优先使用引导类加载器加载核心类,因此你定义的 java.lang.String
仍无法被 JVM 认可。
总结
破坏双亲委派模型后依然无法重写 java.lang.String
类。
原因包括:
- JVM 对核心类的优先加载机制。
java.lang.String
的安全性限制。- JVM 内部对
String
类的特殊处理。
如果尝试修改或替换 String
,可能导致程序运行异常甚至 JVM 崩溃。建议在 Java 开发中不要尝试替换或覆盖核心类。