gpt4 book ai didi

java - 是否可以在运行时用 Java 实现接口(interface)?

转载 作者:太空狗 更新时间:2023-10-29 22:41:14 26 4
gpt4 key购买 nike

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

下面的片段是一个很好的例子来说明我的问题。

代码:

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是一个接口(interface),Clazz 可能会或可能不会在编译时实现。

代码:
public interface ExampleInterface {
public void run();
}

以下代码是我遇到的问题。请注意以下事项:
  • run()仅当 c 是 ExampleInterface 的实例时才被调用.
  • getRunConditions(Clazz c)executeClazz(Clazz c)都是我无权访问的类中的私有(private)方法。
  • 在编译时,Clazz将不包含名为 run() 的方法.
  • ExampleExecutor 不是我的类(class)。我无权访问它
    方式(我什至无法获得该类的实例)。

  • 代码:
    public class ExampleExecutor {
    public void executeClazz(Clazz c) {
    if ((c instanceof ExampleInterface) && getRunConditions(c)) {
    ExampleInterface ex = (ExampleInterface) c;
    ex.run();
    }
    }
    }

    明明 以下方法在语法上是不可能的 ,但这正是我想要实现的目标。基本上,如果 c 还没有实现 ExampleInterface , 设置 c 来实现 ExampleInterface ,然后提供必须覆盖的方法。

    请注意以下事项:
  • extendInterface( Name of Interface )编造语法 一世
    创建是为了说明我的目标。
  • run()必须在这里定义(在运行时)。
  • 我不能使用包装器或代理类作为解决方案。 IE,Clazz对象必须结束实现 ExampleInterface ,我无法使用解决方法。 (如果您想知道原因,请参阅 this link )。

  • 代码:
    public void implementInterface(Clazz c) {
    if (!(c instanceof ExampleInterface)) {
    c.extendInterface(ExampleInterface {
    @Override
    public void run() {
    //code
    }
    });
    }
    }

    澄清一下,我遇到的问题是我需要始终知道何时 run()Clazz 中被调用.如 Clazz永远不执行 ExampleInterface ,不知道什么时候 run()应该叫。

    同时,我也想偶尔添加对 run()的支持。默认情况下不支持时。因为我无法访问 Clazz的创建对象,我不能通过自己实现接口(interface)来做到这一点。

    问题:简单地说,是否可以在运行时实现接口(interface)(并提供所需的方法)?

    注意:虽然唯一的解决方案可能需要反射(如果是,请在下面发布),我使用的库有一个安全管理器,可以阻止所有反射的使用。 IE,一个反射解决方案,以后可能对别人有用,但对我没用。

    另外,我的意思并不是只在我自己的程序中使用库。一个已经在运行的主机应用程序(这是我使用的库的目的)符合并运行我为它编写的代码。如果该应用程序不喜欢我提供的任何代码(IE,与其安全管理器冲突),则该代码甚至不会被编译。

    为什么我需要这样做:

    它与我正在使用的库有关。因为 ExampleExecutor是我无权访问的方法,也无法控制Clazz的创建,无法确定何时 run()被执行。

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

    例如: mouseClicked(CustomMouseEvent evt)可能是作为接口(interface)一部分的方法 CustomMouseListener .有时 Clazz 的实例单击鼠标时我会小心翼翼地工作(因此继承了 CustomMouseListener ),而其他时候则不然。

    不像 Clazz例如,我总是关心鼠标是否被点击,并且总是需要触发事件。

    实际上, ExampleInterface实际上是以下内容:
    public interface CustomMouseListener {
    public void mouseClicked(CustomMouseEvent evt);
    public void mousePressed(CustomMouseEvent evt);
    public void mouseReleased(CustomMouseEvent evt);
    //etc
    }

    最佳答案

    您可以使用 java 检测 API 来(强制)使类适应接口(interface)。这种技术通常被 APM、AOP 框架和分析器用于在运行时将日志记录和度量测量代码注入(inject)目标类。应用程序直接使用这种技术是非常不寻常的。如果我在生产代码中看到这一点,那至少是一个很大的危险信号。

    尽管如此,

    鉴于这些 Clazz:

    package com.sabertiger.example;

    public class Clazz {
    public void purr(){
    System.out.println("Hello world");
    }

    }

    界面
    package com.sabertiger.example;

    public interface ExampleInterface {
    void run();
    }

    执行者
    package com.sabertiger.example;

    public class ExampleExecutor {
    public static void main(String[] args) {
    Clazz c=new Clazz();
    // Normally a ClassCastException
    ExampleInterface i=(ExampleInterface)(Object)(Clazz) c;
    i.run();
    }
    }

    正常运行会产生此错误:
    Exception in thread "main" java.lang.ClassCastException:
    com.sabertiger.example.Clazz cannot be cast to
    com.sabertiger.example.ExampleInterface
    at com.sabertiger.example.ExampleExecutor.main(ExampleExecutor.java:7)

    您可以通过转换类提供缺少的接口(interface)和实现来使其工作:
    package com.sabertiger.instrumentation;

    import java.lang.instrument.ClassFileTransformer;
    import java.lang.instrument.IllegalClassFormatException;
    import java.lang.instrument.Instrumentation;
    import java.security.ProtectionDomain;

    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtMethod;
    import javassist.CtNewMethod;

    public class ExampleInterfaceAdapter implements ClassFileTransformer {

    public static void premain(String agentArgument, Instrumentation instrumentation) {
    // Add self to list of runtime transformations
    instrumentation.addTransformer(new ExampleInterfaceAdapter());
    }

    @Override
    // Modify only com.sabertiger.example.Clazz, return all other unmodified
    public byte[] transform(ClassLoader loader, String className,
    Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
    byte[] classfileBuffer) throws IllegalClassFormatException {

    if(className.matches("com/sabertiger/example/Clazz")) {
    return addExampleInterface(className, classfileBuffer );
    } else {
    return classfileBuffer;
    }
    }

    // Uses javassist framework to add interface and new methods to target class
    protected byte[] addExampleInterface(String className, byte[] classBytecode) {
    CtClass clazz= null;
    try {
    ClassPool pool = ClassPool.getDefault();
    clazz = pool.makeClass(new java.io.ByteArrayInputStream(classBytecode));

    String src=
    "{ "+
    " purr(); "+
    "} ";

    //Add interface
    CtClass anInterface = pool.getCtClass("com.sabertiger.example.ExampleInterface");
    clazz.addInterface(anInterface);

    //Add implementation for run method
    CtMethod implementation = CtNewMethod.make(
    CtClass.voidType,
    "run",
    new CtClass[0],
    new CtClass[0],
    src,
    clazz);
    clazz.addMethod(implementation);

    classBytecode=clazz.toBytecode();
    } catch(Throwable e) {
    throw new Error("Failed to instrument class " + className, e);
    }
    return classBytecode;
    }

    }

    和所需的 MANIFEST.MF
    Manifest-Version: 1.0
    Premain-Class: com.sabertiger.instrumentation.ExampleInterfaceAdapter
    Boot-Class-Path: javassist.jar

    把所有东西都装进一个 jar 里,让它工作:
    jar -tf agent.jar
    META-INF/MANIFEST.MF
    com/sabertiger/instrumentation/ExampleInterfaceAdapter.class

    现在我们可以将 Clazz 传递给 ExampleExecutor
    java -javaagent:agent.jar -classpath ..\instrumentation\bin com.sabertiger.example.ExampleExecutor
    Hello world

    关于java - 是否可以在运行时用 Java 实现接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23769208/

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