TOC
可以自定义修改java的String类吗?
这应该是一道经典的面试题,我以前的回答也无非这两点,都是从自定义类加载器入手的:
- SecurityCheck(SecurityException)限制。
- 自定义类加载器正常必须使用defineClass——>defineClass1,但是defineClass1是个native方法,绕过java命名空间限制也不能自定义加载方式,除非你能修改这个native实现。
但是真的不能对核心类库进行修改吗?
我最近学习了一个新的知识点,可以对其进行修改,这就是指定bootclasspath启动参数的方式,指定优先加载我们自己的类即可。
示例
本示例在java8环境下,java9的机制已经大改了,文后会分析。
这里没有直接修改String类是因为main方法参数使用了,实验起来会不方便,所以修改StringBuilder来展示效果。
其实因为修改String类编译能通过,运行时报找不到main方法,至于原因还未探究。
代码如下:
└─experiment
│ TestClass.class
│
└─java
└─lang
StringBuilder.class
StringBuilder.java
package java.lang;
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
public int lastIndexOf(String str) {
System.out.println(str);
return 1;
}
... 省略其他方法
}
TestClass.java
import java.lang.StringBuilder;
public class TestClass {
public static void main(String[] args) {
StringBuilder builder = new StringBuilder();
int i = builder.lastIndexOf("Success Modify StringBuilder");
System.out.println(i);
}
}
编译运行
❯ javac .\StringBuilder.java
❯ javac .\TestClass.java
❯ java -Xbootclasspath/p:. TestClass
Success Modify StringBuilder
1
# 指定新的 bootclasspath,替换 java.* 包的内部实现
java -Xbootclasspath:<your_boot_classpath> your_App
# a 意味着 append,将指定目录添加到 bootclasspath 后面,后执行
java -Xbootclasspath/a:<your_dir> your_App
# p 意味着 prepend,将指定目录添加到 bootclasspath 前面,先执行
java -Xbootclasspath/p:<your_dir> your_App
Java9以上由于引入模块化系统的机制修改为给模块打patch
确认要修改的类文件已经编译好,并按照对应模块(假设是 java.base)结构存放, 然后,给模块打补丁:
java --patch-module java.base=your_patch yourApp
参考文章
- 请介绍类加载过程,什么是双亲委派模型?