一尘不染

是否可以在Java运行时实现接口?

java

我正在一个项目中,该项目有很多由库创建的对象,并且无法访问这些对象的创建过程。

以下代码片段很好地说明了我的问题。

码:

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在编译时可能会或可能不会实现的接口。

码:

public interface ExampleInterface {
    public void run();
}

以下代码是我遇到的问题。请注意以下几点:

  1. run()仅在c是的实例时调用ExampleInterface
  2. getRunConditions(Clazz c)并且executeClazz(Clazz c)都是我无法访问的类中的私有方法。
  3. 在编译时,Clazz 包含名为的方法run()
  4. ExampleExecutor 不是 我的课程。我无法以任何方式访问它(我什至无法获得该类的实例)。

码:

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,然后提供必须重写的方法。

请注意以下几点:

  1. extendInterface( Name of Interface)是我为了说明我的目标而创建 的组合语法
  2. run() 必须 在运行时在这里定义。
  3. 我不能使用包装器或代理类作为解决方案。IE,该Clazz对象必须最终实现ExampleInterface,而我不能使用解决方法。(如果您想知道原因,请参考 此链接 )。

码:

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()执行。

我之所以需要知道何时run()执行,是因为实际上run()是一个事件处理程序,它是我正在使用的库的一部分。

例如:mouseClicked(CustomMouseEvent evt)可能是接口中一部分的方法CustomMouseListener。有时候,Clazz当我单击鼠标(因此继承了CustomMouseListener)时,我正在使用的实例会很在意,而其他时候却没有。

Clazz实例不同,我始终关心是否单击了鼠标,并且始终需要触发事件。

实际上,ExampleInterface实际上是以下情况:

public interface CustomMouseListener {
    public void mouseClicked(CustomMouseEvent evt);
    public void mousePressed(CustomMouseEvent evt);
    public void mouseReleased(CustomMouseEvent evt);
    //etc
}

阅读 246

收藏
2020-12-03

共1个答案

一尘不染

提出建议的唯一方法是使用字节码Instrumentation。您可以添加一个代理,该代理在加载之前更改要修改的clazz的字节码。

在加载时需要执行此操作的原因是,许多JVM不允许您更改字段,而某些JVM不允许您在类加载后添加方法。

一个更简单的解决方案是反编译该类,对其进行修改然后再次对其进行编译。假设可以反编译该类,这将节省大量时间和精力。

我正在使用的库中有一个安全管理器,它阻止所有反射的使用

这是一个奇怪的选择,因为您可以在调用库之前放置自己的SecurityManager,并且它不能阻止您执行任何操作。

2020-12-03