5
class SimpleTest {
    void met( Object a ) {
        println "Object"
    }

    void met( String b ) {
        println "String"
    }

    static main( args ) {
        SimpleTest i = new SimpleTest()
        i.met(null)
    }
}

此代码将产生输出“对象”。它不会选择最专业的方法版本。在这种情况下,String 比 Object 更专业,因此该规则不适用。

4

1 回答 1

8

Groovy 使用距离计算方法。基本上,如果您将类和接口想象为图中的节点并且它们通过它们的继承关系连接,那么我们会寻找从给定参数类型(参数的运行时类型)到我们的参数类型(静态类型方法参数有)。连接有不同的权重,基本上去超类意味着我认为距离为 3,到接口 1,包装原语也是 1,vargs 包装也有权重(并且不能再在图中真正表示,所以抱歉图片略有失败)

在 null 的情况下,这当然不能工作。这里我们改为查看参数类型到 Object 的距离。虽然非空情况是最可能的特殊方法,但我们对空部分采用最通用的方法。在 Java 中,您通常会使用静态类型或使用强制转换来确保选择什么。在 Groovy 中,我们没有静态类型,并且通常无法正确确定最特殊的类型。因此,我们决定采用最通用的方法来代替这种情况。一般来说,它工作得很好。

然后对象有点像一个后备,它允许你集中处理空值。在未来的版本中,我们可能会允许使用显式的 null 类型,如果存在的话,它将优先于 Object。

虽然您经常可以直接看到类的距离方法,但对于接口来说它有点复杂。基本上算法是这样的:如果我当前的类直接实现了我们正在寻找的接口,那么它与距离 1 匹配。如果该类实现的任何接口具有我们寻找的接口作为父接口,则计算“跳”,直到我们在那里作为距离。但是我们寻找最短的距离。所以我们也以同样的方式看待超类。来自那里的任何搜索结果都将具有 +1 的距离(对于超类跃点)。如果超类搜索给出的距离比在实现接口上搜索的距离短,则取而代之的是超类搜索结果。

至于使用接口处理 null ......如果接口不扩展另一个,则到 Object 的距离为 1。如果是,则为父界面的距离+1。如果扩展多个接口,又是最短路径。

让我们看看 List 和 Integer 是否为 null。
List 扩展 Collection,Collection 扩展 Iterable,Iterable 没有父级。Iterable 的距离为 1,Collection 的距离为 2,List 的距离为 3。整数扩展数字,数字扩展对象。因为我们跳了两次,所以这里的距离为 6(2x3),比另一种情况大得多。是的,这意味着通常我们更喜欢接口。实际上,我们这样做是出于实际原因,因为这种方式被证明最接近实际的编程实践。

于 2013-02-19T14:37:24.147 回答