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

2024-01-08

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

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

Code:

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

Code:

public interface ExampleInterface {
    public void run();
}

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

  1. run()仅当 c 是以下实例时才被调用ExampleInterface.
  2. getRunConditions(Clazz c) and executeClazz(Clazz c)都是我无权访问的类中的私有方法。
  3. 在编译时,Clazz will not包含一个名为run().
  4. 示例执行者是not我的课。我无法以任何方式访问它 方式(我什至无法获得该类的实例)。

Code:

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

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

请注意以下事项:

  1. extendInterface(Name of Interface) is 编造的语法我 创建是为了说明我的目标。
  2. run() must在这里定义(在运行时)。
  3. 我无法使用包装器或代理类作为解决方案。 IE,Clazz对象必须最终实现ExampleInterface,而且我无法使用解决方法。 (参考这个链接 https://stackoverflow.com/questions/23767885/how-to-check-when-a-method-is-run-in-another-class-in-java-method-call-listener如果你想知道为什么)。

Code:

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

澄清一下,我遇到的问题是我需要always知道什么时候run()被叫进Clazz. If Clazz从来没有实施ExampleInterface,我不知道什么时候run()应该被称为。

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

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

NOTE:虽然唯一的解决方案可能需要反射(如果是这样,请将其发布在下面),但我正在使用的库有一个安全管理器,可以阻止所有反射的使用。 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
}

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

尽管如此,

鉴于这些 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();
}

Executor

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)

您可以通过转换类来提供缺少的接口和实现来使其工作:

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 -tf agent.jar
META-INF/MANIFEST.MF
com/sabertiger/instrumentation/ExampleInterfaceAdapter.class

现在我们可以将类传递给示例执行器

java -javaagent:agent.jar -classpath ..\instrumentation\bin com.sabertiger.example.ExampleExecutor
Hello world
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 是否可以在运行时实现接口? 的相关文章

  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • 给定两个 SSH2 密钥,我如何检查它们是否属于 Java 中的同一密钥对?

    我正在尝试找到一种方法来验证两个 SSH2 密钥 一个私有密钥和一个公共密钥 是否属于同一密钥对 我用过JSch http www jcraft com jsch 用于加载和解析私钥 更新 可以显示如何从私钥 SSH2 RSA 重新生成公钥
  • 制作一个交互式Windows服务

    我希望我的 Java 应用程序成为交互式 Windows 服务 用户登录时具有 GUI 的 Windows 服务 我搜索了这个 我发现这样做的方法是有两个程序 第一个是服务 第二个是 GUI 程序并使它们进行通信 服务将从 GUI 程序获取
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • 加速代码 - 3D 数组

    我正在尝试提高我编写的一些代码的速度 我想知道从 3d 整数数组访问数据的效率如何 我有一个数组 int cube new int 10 10 10 我用价值观填充其中 然后我访问这些值数千次 我想知道 由于理论上所有 3d 数组都存储在内
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • getResourceAsStream() 可以找到 jar 文件之外的文件吗?

    我正在开发一个应用程序 该应用程序使用一个加载配置文件的库 InputStream in getClass getResourceAsStream resource 然后我的应用程序打包在一个 jar文件 如果resource是在里面 ja
  • 总是使用 Final?

    我读过 将某些东西做成最终的 然后在循环中使用它会带来更好的性能 但这对一切都有好处吗 我有很多地方没有循环 但我将 Final 添加到局部变量中 它会使速度变慢还是仍然很好 还有一些地方我有一个全局变量final 例如android Pa
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • Eclipse Java 远程调试器通过 VPN 速度极慢

    我有时被迫离开办公室工作 这意味着我需要通过 VPN 进入我的实验室 我注意到在这种情况下使用 Eclipse 进行远程调试速度非常慢 速度慢到调试器需要 5 7 分钟才能连接到远程 jvm 连接后 每次单步执行断点 行可能需要 20 30
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 在mockito中使用when进行模拟ContextLoader.getCurrentWebApplicationContext()调用。我该怎么做?

    我试图在使用 mockito 时模拟 ContextLoader getCurrentWebApplicationContext 调用 但它无法模拟 here is my source code Mock org springframewo
  • 当我从 Netbeans 创建 Derby 数据库时,它存储在哪里?

    当我从 netbeans 创建 Derby 数据库时 它存储在哪里 如何将它与项目的其余部分合并到一个文件夹中 右键单击Databases gt JavaDB in the Service查看并选择Properties This will
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • java.lang.IllegalStateException:驱动程序可执行文件的路径必须由 webdriver.chrome.driver 系统属性设置 - Similiar 不回答

    尝试学习 Selenium 我打开了类似的问题 但似乎没有任何帮助 我的代码 package seleniumPractice import org openqa selenium WebDriver import org openqa s
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐

  • 当测试类没有单独执行时,@SpyBean不会拦截方法调用

    我有多个 WebMvcTest 带注释的测试类 如果单独执行 例如通过mvn Dtest BTest test或通过 IDE 但是 如果它们一起执行 例如通过mvn test or mvn package 一项测试失败 BTest在下面的代
  • AudioKit FFT 转换为 dB?

    第一次发帖 感谢社区的厚爱 我在用AudioKit并尝试向麦克风输入添加频率加权滤波器 因此我尝试了解来自 AudioKit AKFFTTap 的值 目前我正在尝试打印转换为 dB 值的 FFT 缓冲区 for i in 0
  • 如何自动缩放小部件以适应不同的屏幕尺寸?

    我有一个包含 ListTile 的卡片 ListView 在每个列表图块内我都有标题和副标题 我尝试在几部手机 android ios 上调试我的应用程序 对于其中一些手机 字幕文本会溢出卡片小部件 因为它们的屏幕较小 有没有办法根据屏幕尺
  • 点击按钮然后在android中自动发送电子邮件

    我有一个 xml 文件 用户将在其中输入电子邮件 然后当单击提交按钮时 我希望应用程序自动向该电子邮件发送一封包含特定内容的电子邮件 我可以从中获得帮助的任何好的教程或示例 package com example emailtest imp
  • 预加载取决于 Ruby on Rails 中的关联类型

    我有一个多态关联 belongs to resource polymorphic true where resource可以是多种不同的型号 为了简化问题 假设它可以是Order or a Customer 如果它是一个Order我想预加载
  • 安装pbr时出错

    我想在运行 OSX 10 8 5 的计算机上安装 openstack 客户端 作为先决条件 我需要安装 pbr 所以 我做了以下事情 git clone git github com openstack dev pbr git cd pbr
  • 对具有多个条件的元组列表进行排序

    我有一个包含 k 个元素的元组列表 我想先对元素 0 进行排序 然后对元素 1 进行排序 依此类推 我用谷歌搜索 但我仍然不太清楚该怎么做 会是这样的吗 list sort key lambda x x 0 x 1 x k 1 特别是 我想
  • 是否可以在 iPhone 应用程序图标中使用透明度?

    我为我的应用程序创建了一个 57 57 圆形图标 无光泽 其圆外具有透明度 我可以在模拟器和 iPhone 上成功安装该应用程序 它工作得很好 而且看起来很棒 但是 我可以向 Apple 提交透明的图标吗 他们会接受吗 我找不到任何图标具有
  • Cocos2d-x - 如何将CCLayer的一部分设置为透明?

    我是新手cocos2d x我需要你的帮助 我需要使图层的触摸部分透明 如何使图层的一部分透明 我曾想过使用 ClippingNode 但我找不到示例或文档 我使用C 谢谢 在所有cocos2d x版本中添加的TestCpp项目中 您可以找到
  • java 清单类路径与-classpath

    我试图找出可执行 jar 文件的一个奇怪问题 xyz jar 在清单文件 中有一个类路径 并且依赖于 abc jar 库 不幸的是 xyz jar 中的清单类路径不正确 为了避免灾难 我正在更新执行命令以使用 java classpath
  • 为什么 this.evaluate 不能正确返回 DOM 节点?

    我试图通过以下方式从网页获取对象evaluate 方法 这样我就可以在范围之外使用它evaluate 使用名称选择的元素symbol is a
  • “不存在”和“不存在”有什么区别?

    有什么区别not in and not exists在 Oracle 查询中 我什么时候使用not in And not exist 和 之间的不同NOT IN and 不存在变得清楚哪里有NULL结果中包含的值 例如 create tab
  • 使用硬件加速的自定义 Android 视图中的部分失效

    我的应用程序中有一个自定义视图 它填充了整个活动 在大多数情况下 当我想刷新控件时我调用invalidate 没有任何参数 但是 在某些情况下 我只更改控件的一小部分区域 我会调用invalidate Rect 以避免重绘整个屏幕 这很重要
  • 向 JTable 和数据库 (phpMyAdmin) 添加一行?

    initComponents try ResultSet res statement executeQuery SELECT FROM banh ResultSetMetaData RSMD res getMetaData NumberOf
  • 如何在 Xamarin.Forms 中删除(Android)应用程序标题栏?

    我是否可以在 Xamarin Forms 中删除应用程序的标题栏 我正在开发 Xamarin Forms Portable 项目 我尝试了很多解决方案 但都不起作用 我什至无法启动应用程序 第一次尝试我尝试将其添加到我的 AndroidMa
  • TypeScript:为同一项目中的不同文件声明不同的库/引用

    我有一个用 TypeScript 编写的项目 我同时使用 dom 和 Web Workers 因此我在某些文件中需要 webworker d ts 库 在其他文件中需要 dom d ts 我已经尝试将 webworker 添加到 tscon
  • Dynamo DB 中的自动递增计数器

    我正在尝试在 dynamo 数据库中实现哈希键的自动递增计数器 但我的代码对于并发事务失败 任何帮助实现该功能的帮助将不胜感激 我是堆栈溢出的新手 可能无法正确指定它 任何实施都会有所帮助 您有两种选择 使用 dynamo db 原子计数器
  • YAML 媒体类型?

    通过 HTTP 发送使用 YAML 构建的数据时最合适的媒体类型 正式的 MIME 类型 是什么 为什么 没有已注册的应用类型 http www iana org assignments media types application or
  • 为什么在单独的模型文件中使用 model.export ?

    在查看一些有关拆分模型数据的 Stackoverflow 答案时 我看到了两种不同的格式 见下文 var UserSchema mongoose Schema name String module exports mongoose mode
  • Java 是否可以在运行时实现接口?

    我正在开发一个项目 其中有很多由库创建的对象 并且我无法访问这些对象的创建过程 以下片段是说明我的问题的一个很好的例子 Code public class Clazz The contents of Clazz are irrelevant