Chr*_*tof 5 java groovy overloading
您好Groovy和Java专家
我们遇到了一种奇怪的Groovy行为,在我们看来,它就像是语言的局限性(或错误)。我们的长篇文章归结为以下问题:
当方法重载在起作用时,Groovy中的方法选择是否有意选择接口而不是子类?
我们创建了一个简单的示例来说明这种情况:
interface A {}
interface B {}
class C implements A, B {}
class D extends C {}
class Foo {
void add(A a) { System.out.println("A"); }
void add(B b) { System.out.println("B"); }
void add(C c) { System.out.println("C"); }
}
D d = new D();
new Foo().add(d);
Run Code Online (Sandbox Code Playgroud)
我们本来希望该方法Foo#add(C c) 被调用,但是会引发以下异常:
groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method Foo#add.
Cannot resolve which method to invoke for [class D] due to overlapping prototypes between: [interface A] {interface B]
Run Code Online (Sandbox Code Playgroud)
这似乎是意外的,Foo#add(C c)显然是最佳人选。因此,我们在Java中测试了此确切的代码,并且该代码按预期工作:Foo#add(C c)调用了方法。
然后,我们继续进行进一步研究,并通过源代码进行调试。具体来说,有一个方法可以选择要调用的方法:groovy.lang.MetaClassImpl#chooseMostSpecificParams
在那里,在所有3个(在我们的示例中)#add方法之间计算出一个距离-最后,在这里: org.codehaus.groovy.runtime.MetaClassHelper#calculateParameterDistance(java.lang.Class, org.codehaus.groovy.reflection.CachedClass)
该算法然后相继增加距离。首先,因为在我们的例子中,参数d(D的实例)不是接口,也不是原始类型,所以添加了17的距离。其次,直到那时,才检查类型C和D是否相同,或者D是否从C继承。对于C高于D的每个继承级别,将距离3相加。因此,我们的距离为20。
然后将此距离20(在对对象参数类型进行一些额外的移位(例如对对象参数类型的惩罚之后))与两个添加方法(其签名中只有接口)的距离进行比较,结果是未选择方法#add(C c) /考虑。发生该异常是因为,实际上,现在有2种方法(#add(A a)和#add(B b))具有相同的距离,并且运行时无法知道要选择哪种方法。
也许有人可以向我们解释为什么它在Groovy中的处理方式与Java不同?
这听起来像是这个(未解决的)错误的更具体的情况。我建议填写一个关于它的 JIRA。
Groovy 的方法选择在运行时使用多个分派或多方法进行工作,因为它是一种具有可选类型的动态语言,而 Java 使用单分派,其中要调用的方法是在编译时定义的。
以下代码适用于 Java,但在 Groovy 中会失败并出现断言错误:
public class SingleMult {
public static void main(String[] args) {
A a = new B();
assert(new SingleMult().method(a) == "A");
}
String method(A a) { return "A"; }
String method(B b) { return "B"; }
}
interface A {}
class B implements A {}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3487 次 |
| 最近记录: |