2013-06-26 28 views
5

我使用Javassist创建一个类。而在一个测试套件,当第二个测试试图创建相同的类,它在pool.makeClass(...)失败,因为该类被冻结(即已经通过toClass()创建。Javassist:重新创建一个类 - 先删除,或解冻()并修改?

什么是克服这种方式?理想的情况下,第一个试验应删除类不知何故 - 也许从类加载器卸载 - 但只要我阅读in JLS,卸载操作是不可靠的

因此,也许解决办法是在类创建代码是否存在来检查,如果确实如此,defrost()它,删除所有成员等,并重新创建它。

任何其他的想法?

或者是否有一些可靠的方法通过Javassist删除类?

+0

从'ClassLoader'卸载并非不可靠 - 这是不可能的。如果一个类*和*它的'ClassLoader'变得不可访问,那么一个类可能会被卸载,但是因为每个类引用了它的加载器,这意味着这个加载器加载的所有类都必须变得无法访问。但是你可以(重新)使用*不同的''ClassLoader'创建类。那么,从形式上来说,它是一个不同的类,然后同名(也可能是相同的字节码)。 – Holger

+0

这似乎是答案...如果你这样说,我会接受。 –

回答

4

您无法从ClassLoader卸载单个班级。如果一个类和它的ClassLoader变得无法访问,但是由于每个类引用它的加载器,这意味着由该加载器加载的所有类都必须变得无法访问,所以类可能会被卸载。

但是,您可以使用不同的ClassLoader(重新)创建班级。那么,从形式上来说,它是一个不同的类,然后同名(也可能是相同的字节码)。如果在测试用例中执行的代码在堆中没有引用,则在测试之后可能收集到ClassLoader及其类。

+0

好的,但是如果第二个ClassLoader中的已加载的类引用了第一个ClassLoader的另一个类,那么我们是否也应该将所有引用类型添加到第二个ClassLoader? – Pooya

+1

@Пуя:这取决于几个因素。如果C1将关联的类加载请求委派给C2,则由ClassLoader C1定义的类可能具有对由另一个“ClassLoader”C2定义的运行时类型解析的类的引用。如果C2是C1的* parent *加载器,则这是标准行为。但这意味着C2中的这些类保持不变,并且C2保持可到达并且在C1被使用时不能被垃圾收集。因此,如果您想一次修改多个相关的类,则必须在新的'ClassLoader'中重新定义它们。 – Holger

+0

而如果新的类的实例是打算在那里一个超类或接口类型,预计地方,以取代旧的,特定的基本类型或接口*必须*解析为同一运行时类型,允许直接替换。 – Holger

0

我得到了同样的问题,我解决了它这种方式,可能无法办理你的测试用例:

让CtClass您的类的私有静态变量。

创建一个检查CtClass是否已经构建的方法。 如果未构建CtClass,请调用构建它的方法,否则返回该CtClass。

确保所有测试都使用新方法。

所以,如果你有N测试,只是第一个将尝试建立CtClass,其余的将有静态CtClass变量。

相关问题