gpt4 book ai didi

java - 仅使用私有(private)构造函数扩展类

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:56:28 25 4
gpt4 key购买 nike

问题是:我有一个只有私有(private)构造函数可用的类(我不能修改它的源代码),我需要扩展它。

由于反射允许我们在需要时创建此类的实例(通过获取构造函数并调用 newInstance()),是否有任何方法可以创建此类的扩展版本的实例(我的意思是,真的有任何方法,即使它反对 OOP)?

我知道,这是一个不好的做法,但看起来我别无选择:我需要拦截对一个类的一些调用(它是一个单例,它不是一个接口(interface)实现,所以动态代理在这里不起作用) .

最小示例(按要求):

public class Singleton {
static private Singleton instance;

private Singleton() {
}

public static Singleton getFactory() {
if (instance == null)
instance = new Singleton();
return instance;
}

public void doWork(String arg) {
System.out.println(arg);
}}

我想做的就是构建我自己的包装器(就像这个)

class Extension extends Singleton {
@Override
public void doWork(String arg) {
super.doWork("Processed: " + arg);
}}

然后使用反射将其注入(inject)工厂:

Singleton.class.getField("instance").set(null, new Extension());

但我看不到任何构造此类对象的方法,因为它的父类(super class)的构造函数是私有(private)的。问题是“这是否可能”。

最佳答案

如果

有可能( 但是一个糟糕的 hack)
  • 您拥有带有私有(private)构造函数的类的源代码,或者您可以从字节码重构它
  • 该类由应用程序类加载器加载
  • 你可以修改jvm的类路径

您可以创建一个与原始类二进制兼容的补丁。

我将在下一节中调用您要扩展的类 PrivateConstructorClass。

  1. 获取PrivateConstructorClass 的源代码并将其复制到源文件中。不得更改包和类名称。
  2. PrivateConstructorClass 的构造函数从私有(private)更改为 protected 。
  3. 重新编译修改后的PrivateConstructorClass源文件。
  4. 将编译后的类文件打包成jar包。例如。称为“patch.jar”
  5. 创建一个扩展第一个类的类,并根据 patch.jar 中的类编译它
  6. 更改 jvm 的类路径,使 patch.jar 成为类路径中的第一个条目。

现在有一些示例代码可以让您检查它是如何工作的:

期望以下文件夹结构

+-- workspace
+- private
+- patch
+- client

private文件夹中创建PrivateConstructor

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);
}
}

现在针对 patch.jar 编译 client 文件夹的源文件>

 $ 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

关于java - 仅使用私有(private)构造函数扩展类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19492214/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com