2012-04-06 46 views
7

我有能力在编译时扩展类,但是我需要能够在运行时使用已实例化的超类的实例创建此子类的实例。Java:在运行时扩展类

这在理论上应该是可能的,因为超类构造函数已经在子类构造函数之前被调用过。

我没有充分地访问该程序来将实例更改为我的子类,也无法中断原始实例化。

使用案例:有一个现有的X类实例数组。我的代码在之后加载。我需要重写其中一个实例X的方法,其中我的加载子类Y扩展了X.父程序仅通过该数组访问对象,所以我想用Y实例替换该数组元素,但它需要表现得好像它最初实例化到该数组中一样。我不能随便附上超类实例和转发调用,并且在重新实例化超类时遇到困难。

我希望更清楚。

+3

请重新说明问题。 – 2012-04-06 16:11:11

+1

您是否还可以提供您实际尝试完成的示例?而不仅仅是你想要的,但可能不可能的方法。 – millimoose 2012-04-06 16:16:27

+0

假设现有行“public static Foo foo = new Foo();”我无法改变。我有“public class Bar extends Foo”,我想做“foo = new Bar(...)”,就好像第一行是“public static Foo foo = new Bar()”。 – JAKJ 2012-04-06 16:24:48

回答

5

重申您正在尝试做的事情。

在JVM中,存在ClassA的实例。您想要动态修改ClassA的类Heiarchy,以便存在一个名为ClassB的新类,该ClassB源自ClassA。然后,您想实例化ClassB的一个实例,但将它的子类实现为ClassA的现有实例。就像内存替换一样。您可能想要查看http://www.jboss.org/javassist。你需要做的是替换ClassLoader,然后确定何时加载ClassA,然后实例化。然后你需要构造ClassB并返回它。

更新

多一点研究后还是有,你可以做你想做的可能性。 IDE就像Eclipse一样在调试时支持HotSwaping方法实现。他们使用Instrumentation API。

http://zeroturnaround.com/blog/reloading_java_classes_401_hotswap_jrebel/

您可以替换方法体,但不能添加或删除方法本身。因此,尽管您无法将类型更改为新类型,但您可以将新方法的实现完全替换为新实现。

+0

我不会在运行时更改继承,但仅在其超类已实例化时才实例化子类。 – JAKJ 2012-04-06 16:26:37

+0

@JAKJ答案依然如此。你有一个现有的对象,你想适应另一种类型的对象。如果你可以控制这个新对象的初始返回点,那么你可以调整它并返回你想要的实例。我建议你用你的用例更新你的问题,而不是你认为的解决方案。 – 2012-04-06 16:28:36

+0

我没有能力替换classloader,因为我的类在超类之后加载,也不能使用第三方运行时。这必须在Java内。 – JAKJ 2012-04-06 16:31:29

1

你看过Java代理吗?

这里是从Javadoc中一个片段:

“的动态代理类(简称为下面的代理类)是当在创建类,它实现在运行时指定的接口的列表的类”

+0

它看起来像代理是为接口,而不是类。 – JAKJ 2012-04-06 16:27:25

3

我会建议使用cglib

CGLIB是一个功能强大,高性能和高质量代码生成 库,它是用来扩展Java类和实现接口 在运行时

你在这里可以找到一些例子: https://github.com/cglib/cglib/wiki

2

我不知道这是否是一种溶剂,但如果你有

public static Foo foo = new Foo(); 

,并要与延伸富 使酒吧的包装为Foo和使用反射让FOO点到你的酒吧例如酒吧来取代它。

public class Foo extends Bar { 
    private bar; 
    public Foo(Bar oldInstance) { 
    this.bar = oldInstance; 
    } 
} 

// exception handling ommitted 
public static void onStartup() { 
    Class fooRefClass = FooRef.class; 
    Field fooRef = fooRefClass.getDeclaredField("foo"); 

    Foo foo = (Foo)fooRef.get(null); 
    Bar bar = new Bar(foo); 
    fooRef.set(null, bar); 

}

至于说我不知道​​这是可能的,你的情况。