java - 字节好友 : Create implementation for an abstract class

标签 java class interface bytecode byte-buddy

我想使用 Byte Buddy 在运行时为抽象类创建一个实现,我遇到了一个问题,当从创建的实例。我有一个像这样的现有 abstract 类(我实际上无法修改它,它实际上包含更多逻辑):

public abstract class Algorithm {
    abstract int execute();
}

使用以下最小样本,我希望我的Algorithm 实例返回一个常量值:

Class<?> type = new ByteBuddy()
                        .subclass(Algorithm.class)
                        .method(ElementMatchers.named("execute"))
                        .intercept(FixedValue.value(42))
                        .make()
                        .load(classLoader, ClassLoadingStrategy.Default.WRAPPER)
                        .getLoaded();
Algorithm instance = (Algorithm) type.newInstance();
System.out.println(myInstance.execute());

然而,这会导致以下异常:

Exception in thread "main" java.lang.AbstractMethodError: package.Algorithm.execute()I

(当我实验性地将 Algorithm 更改为 interface 时,一切正常,但这并没有解决我的具体问题)。

最佳答案

这可能会让您感到惊讶,但如果您使用相同的类加载器设置使用 javac 生成相同的代码,则会发生完全相同的事情。您观察到的是 JLS 中如何指定包隐私的暗示。您的非接口(interface)

public abstract class Algorithm {
  abstract int execute(); 
}

定义了一个包私有(private)的方法。由于您没有为生成的类定义自定义名称,因此 Byte Buddy 会生成一个具有随机名称的子类,该子类位于同一包中。 Byte Buddy 确实进一步发现 executable 方法可从生成的子类中重写,并完全按照您的预期实现它。

但是,您正在使用 ClassLoadingStrategy.Default.WRAPPER 策略加载类,该类创建一个加载 Algorithm 的新子类加载器。在 Java 中,在运行时,两个包只有当包的名称相同并且两个包都由相同的ClassLoader加载时才相等.对于您的情况,后一种情况不成立,因此 JVM 不再将多态性应用于 execute 类。通过调用

((Algorithm) type.newInstance()).execute();

因此,您调用的不是生成的方法,而是原始的抽象方法。因此 - 根据 JLS - 抛出 AbstractMethodError

要解决此问题,您需要使用默认的 INJECTION 策略在同一个包中加载生成的类,或者您必须将 execute 定义为 public(这在定义接口(interface)时是隐含的)或 protected 方法,以便您期望的多态性规则适用。作为第三种选择,您可以通过以下方式调用正确的运行时方法

type.getDeclaredMethod("execute").invoke(type.newInstance());

关于java - 字节好友 : Create implementation for an abstract class,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34709310/

相关文章:

java - 什么是 “the Interface” 以及如何对 “Against” 进行编程?

c# - 如何返回以接口(interface)为返回类型的接口(interface)的实现?

c# - 接口(interface)设计实现错误: . ..无法实现...因为它没有匹配的返回类型

class - 通过使用具体类而不是接口(interface),编译后的 js 的大小减少了多少

java - 如何在viewpager中的fragment中保存recyclerview的状态?

Java Hibernate createSQLQuery 使用 addEntity

java - 不可变链表的拆分器

node.js - 如何在另一个类中使用类函数?

c++ - 指向类数据成员 "::*"的指针

网站上的Java小程序不扫描其他网站