如果_ _
- 您拥有带有私有构造函数的类的源代码,或者您可以从字节码重构它
- 该类由应用程序类加载器加载
- 你可以修改jvm的类路径
然后,您可以创建一个与原始类二进制兼容的补丁。
我将在下一节中调用您要扩展 PrivateConstructorClass 的类。
- 获取源代码
PrivateConstructorClass
并将其复制到源文件中。包名和类名不得更改。
- 将构造函数
PrivateConstructorClass
从私有更改为受保护。
- 重新编译修改后的源文件
PrivateConstructorClass
。
- 将编译好的类文件打包成一个jar包。例如称为“patch.jar”
- 创建一个扩展第一个类的类,并针对 patch.jar 中的类进行编译
- 更改 jvm 的类路径,使 patch.jar 成为类路径中的第一个条目。
现在有一些示例代码可以让您检查它是如何工作的:
期望以下文件夹结构
+-- workspace
+- private
+- patch
+- client
在文件夹中创建PrivateConstructor
类private
public class PrivateConstructor {
private String test;
private PrivateConstructor(String test){
this.test = test;
}
@Override
public String toString() {
return test;
}
}
在文件夹中打开命令提示符private
,编译并打包。
$ javac PrivateConstructor.java
$ jar cvf private.jar PrivateConstructor.class
现在在文件夹中创建补丁文件patch
:
public class PrivateConstructor {
private String test;
protected PrivateConstructor(String test){
this.test = test;
}
@Override
public String toString() {
return test;
}
}
编译并打包
$ javac PrivateConstructor.java
$ jar cvf patch.jar PrivateConstructor.class
现在是有趣的部分。
在客户端文件夹中创建一个扩展 PrivateConstructor 的类。
public class ExtendedPrivateConstructor extends PrivateConstructor {
public ExtendedPrivateConstructor(String test){
super(test);
}
}
和一个主要的类来测试它
public class Main {
public static void main(String str[]) {
PrivateConstructor privateConstructor = new ExtendedPrivateConstructor("Gotcha");
System.out.println(privateConstructor);
}
}
现在编译client
文件夹的源文件patch.jar
$ javac -cp ..\patch\patch.jar ExtendedPrivateConstructor.java Main.java
现在用类路径上的两个 jar 运行它,看看会发生什么。
如果 位于patch.jar
之前,private.jar
则从PrivateConstructor
加载该类,patch.jar,
因为应用程序类加载器是URLClassLoader
.
$ java -cp .;..\patch\patch.jar;..\private\private.jar Main // This works
$ java -cp .;..\private\private.jar;..\patch\patch.jar Main // This will fail