首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在静态编译的Groovy中调用最具体的重载

在静态编译的Groovy中调用最具体的重载
EN

Stack Overflow用户
提问于 2019-11-08 17:33:15
回答 1查看 72关注 0票数 1

由于Groovy动态方法调度,下面的代码打印ABC,这正是我所期望的。在添加@CompileStatic之后,我的代码中断,只打印AAA。如何保留动态方法选择的逻辑并静态编译代码?

代码语言:javascript
复制
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:

代码语言:javascript
复制
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
}
EN

回答 1

Stack Overflow用户

发布于 2019-11-08 19:03:03

从Groovy2.1.0开始,您可以使用@groovy.transform.CompileDynamic注释来声明必须动态调用代码的哪一部分。在这种情况下,您可以将show(a)方法调用提取到使用@CompileDynamic注释的单独方法中。代码的其余部分将被静态编译,但show(a)方法调用有一个小例外。

考虑以下示例:

代码语言:javascript
复制
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类型:

代码语言:javascript
复制
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()方法的实现:

代码语言:javascript
复制
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)方法视为未使用的,因为没有显式调用这两个方法中的任何一个。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58763881

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档