【发布时间】:2020-09-30 21:55:00
【问题描述】:
我有两个类A 和B,都定义了具有共同签名的方法foo()(不接受任何内容,返回无效)。它们没有声明此方法的通用基类(或接口)。我想在 As 或 B 上调用这个方法,只要他们能响应这个调用。这种方法称为Duck Typing。
我知道有一条指令叫invokedynamic:
invokedynamic 指令的每个实例都称为动态调用 地点。动态调用站点最初处于未链接状态,这 表示没有指定调用站点调用的方法。 如前所述,动态调用站点通过以下方式链接到方法 引导方法的手段。动态调用站点的引导方法是 编译器为动态类型语言指定的方法 JVM 调用一次以链接站点。返回的对象 从引导方法永久确定调用站点的 行为。
所以我尝试使用MethodHandles 来实现这一目标。示例如下:
public static class A {
public void foo() {
}
}
public static class B {
public void foo() {
}
}
public static void main(String[] args) throws Throwable {
final MethodHandle foo = MethodHandles.lookup()
.findVirtual(A.class, "foo", MethodType.methodType(void.class));
foo.invoke(new B());
}
当然,我有:
Exception in thread "main" java.lang.ClassCastException: Cannot cast Main$B to Main$A
at sun.invoke.util.ValueConversions.newClassCastException(ValueConversions.java:461)
at sun.invoke.util.ValueConversions.castReference(ValueConversions.java:456)
at Main.main(Main.java:30)
我清楚地看到了invokedynamic 和MethodHanle 之间的区别。我看到问题在于foo MethodHandle 绑定到class A,而不是class B。但是在这种特殊情况下,我有可能以某种方式利用invokedynamic 吗?
我为什么需要这个?这是我的小型研究项目的一部分。我正在尝试深入了解方法句柄,并且我想在从字段和方法中检索到的注释实例上调用常用方法。我无法在 Java 中为注释定义基类,因此我希望尽可能实现这种鸭子类型,而不是使用 instanceof 链和类强制转换或使用违反访问权限的反射检索这些值。
谢谢。
【问题讨论】:
-
您当前的问题与
invokedynamic或任何问题无关,您需要一个正确类的实例来调用实例方法。当然,您不能在B对象上调用A方法,因为A实现foo()可能取决于仅存在于A中的字段/数据/私有函数。invokedynamic也需要一个实例。在静态方法上,您可以将null作为this参数传递给invoke,但实际上:只有当您已经拥有该对象的实例时,鸭子类型才有效,而您缺少atm :)
标签: java annotations duck-typing methodhandle invokedynamic