由于Groovy动态方法调度,下面的代码打印ABC,这正是我所期望的。在添加@CompileStatic之后,我的代码中断,只打印AAA。如何保留动态方法选择的逻辑并静态编译代码?
class PatternMatching {
static void main(String[] args) {
[new A(), new B(), new C()].each {
show it
}
}
static void show(A a) {
print 'A'
}
static void show(B b) {
print 'B'
}
static void show(C c) {
print 'C'
}
}
class A {}
class B extends A {}
class C extends A {}令人惊讶的是,即使是带有cast的instanceof也完全不适用于静态编译的Groovy:
if (it instanceof A) {
show it as A
} else if (it instanceof B) {
show it as B
} else if (it instanceof C) {
show it as C
}发布于 2019-11-08 19:03:03
从Groovy2.1.0开始,您可以使用@groovy.transform.CompileDynamic注释来声明必须动态调用代码的哪一部分。在这种情况下,您可以将show(a)方法调用提取到使用@CompileDynamic注释的单独方法中。代码的其余部分将被静态编译,但show(a)方法调用有一个小例外。
考虑以下示例:
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
@CompileStatic
class PatternMatching {
static void main(String[] args) {
[new A(), new B(), new C()].each {
callShowDynamically(it)
}
}
@CompileDynamic
static void callShowDynamically(A a) {
show a
}
static void show(A a) {
print 'A'
}
static void show(B b) {
print 'B'
}
static void show(C c) {
print 'C'
}
}
@CompileStatic
class A {}
@CompileStatic
class B extends A {}
@CompileStatic
class C extends A {}下面是反编译后的PatternMatching.class的并排比较。(右边的那个表示具有@CompileDynamic方法的静态编译的类。)

下面是each闭包反编译的类字节码的并列比较:

注意一个细节-即使我们使用用@CompileDynamic注释的callShowDynamically()方法,它在字节码级别的调用使用静态编译的类型,它甚至将其强制转换为A类型:
public static void main(String... args) {
final class _main_closure1 extends Closure implements GeneratedClosure {
public _main_closure1(Object _outerInstance, Object _thisObject) {
super(_outerInstance, _thisObject);
}
public Object doCall(Object it) {
return PatternMatching.callShowDynamically((A)ScriptBytecodeAdapter.castToType(it, A.class));
}
public Object call(Object args) {
return this.doCall(args);
}
public Object call() {
return this.doCall((Object)null);
}
@Generated
public Object doCall() {
return this.doCall((Object)null);
}
}
DefaultGroovyMethods.each(ScriptBytecodeAdapter.createList(new Object[]{new A(), new B(), new C()}), new _main_closure1(PatternMatching.class, PatternMatching.class));
}使此调用“动态”的是PatternMatching.callShowDynamically()方法的实现:
public static Object callShowDynamically(A a) {
CallSite[] var1 = $getCallSiteArray();
return var1[0].callStatic(PatternMatching.class, a);
} 该方法使用Groovy's MOP (Meta-Object Protocol)来检测(基于特定于运行时的类型)该类型调用的最具体的方法是什么。在编译器级别,它仍然只是PatternMatching.callShowDynamically((A)value)方法调用,所以它不知道可能会调用其他方法。这就是为什么您的IntelliJ想法将show(B b)和show(C c)方法视为未使用的,因为没有显式调用这两个方法中的任何一个。
https://stackoverflow.com/questions/58763881
复制相似问题