我正在一个项目中,该项目有很多由库创建的对象,并且无法访问这些对象的创建过程。
以下代码片段很好地说明了我的问题。
码:
public class Clazz { //The contents of Clazz are irrelevant //Clazz is NOT my class. I have no access to its internal structure. //However, I do have access to Clazz objects that were created elsewhere. }
ExampleInterface 是Clazz在编译时可能会或可能不会实现的接口。
ExampleInterface
public interface ExampleInterface { public void run(); }
以下代码是我遇到的问题。请注意以下几点:
run()
getRunConditions(Clazz c)
executeClazz(Clazz c)
Clazz
public class ExampleExecutor { public void executeClazz(Clazz c) { if ((c instanceof ExampleInterface) && getRunConditions(c)) { ExampleInterface ex = (ExampleInterface) c; ex.run(); } } }
显然 ,以下方法在语法上不可行 ,但这是我正在尝试实现的方法。基本上,如果c尚未实现ExampleInterface,请将c设置为Implement ExampleInterface,然后提供必须重写的方法。
请注意以下几点:
extendInterface(
Name of Interface
)
public void implementInterface(Clazz c) { if (!(c instanceof ExampleInterface)) { c.extendInterface(ExampleInterface { @Override public void run() { //code } }); } }
为了澄清,我遇到的问题是我需要 始终 知道何时run()调用in Clazz。如果Clazz没有实现ExampleInterface,我不知道何时run()应该调用。
同时,我还希望偶尔增加对run()默认情况下不支持的支持。由于我无权访问Clazz对象的创建,因此无法通过自己实现接口来实现。
问:简单地说,是否可以在运行时实现接口(并提供所需的方法)?
注意: 虽然唯一的解决方案可能需要反射(如果需要,请在下面发布),但是我正在使用的库具有一个安全管理器,该管理器阻止所有反射的使用。IE,一种反射性解决方案将来可能对其他人有用,但对我而言将毫无用处。
另外,我并不是说只在自己的程序中使用一个库。一个已经在运行的主机应用程序(这就是我正在使用的库所针对的)符合并运行我为其编写的代码。如果该应用程序不喜欢我提供的任何代码(即,IE与其安全管理器发生冲突),则该代码甚至不会被编译。
为什么我需要这样做:
它与我正在使用的库有关。因为这ExampleExecutor是我无法访问的方法,并且我无法控制Clazz的创建,所以我无法确定何时run()执行。
ExampleExecutor
我之所以需要知道何时run()执行,是因为实际上run()是一个事件处理程序,它是我正在使用的库的一部分。
例如:mouseClicked(CustomMouseEvent evt)可能是接口中一部分的方法CustomMouseListener。有时候,Clazz当我单击鼠标(因此继承了CustomMouseListener)时,我正在使用的实例会很在意,而其他时候却没有。
mouseClicked(CustomMouseEvent evt)
CustomMouseListener
与Clazz实例不同,我始终关心是否单击了鼠标,并且始终需要触发事件。
实际上,ExampleInterface实际上是以下情况:
public interface CustomMouseListener { public void mouseClicked(CustomMouseEvent evt); public void mousePressed(CustomMouseEvent evt); public void mouseReleased(CustomMouseEvent evt); //etc }
提出建议的唯一方法是使用字节码Instrumentation。您可以添加一个代理,该代理在加载之前更改要修改的clazz的字节码。
在加载时需要执行此操作的原因是,许多JVM不允许您更改字段,而某些JVM不允许您在类加载后添加方法。
一个更简单的解决方案是反编译该类,对其进行修改然后再次对其进行编译。假设可以反编译该类,这将节省大量时间和精力。
我正在使用的库中有一个安全管理器,它阻止所有反射的使用
这是一个奇怪的选择,因为您可以在调用库之前放置自己的SecurityManager,并且它不能阻止您执行任何操作。