为什么在Groovy(版本2.4.5)中调用super会错过父类?

为什么在Groovy(版本2.4.5)中调用super会错过父类?,groovy,Groovy,鉴于课程安排如下: class GrandParent { String init() { return "GrandParent init, " } } class Parent extends GrandParent { String init() { return super.init() + "Parent init, " } } class ChildInitAndVisit extends Paren

鉴于课程安排如下:

class GrandParent { 
    String init() { 
        return "GrandParent init, " 
    } 
}

class Parent extends GrandParent { 
    String init() { 
        return super.init() + "Parent init, " 
    } 
}

class ChildInitAndVisit extends Parent { 
    String init() { 
        return super.init() + "Child init" 
    }

    String visit() { 
        return super.init() + "Child visit" 
    } 
}

class ChildVisitOnly extends Parent { 
    String visit() { 
        return super.init() + "Child visit" 
    } 
}
然后以这种方式使用它们:

iv = new ChildInitAndVisit()
println "ChildInitAndVisit - calling init() -> ${iv.init()}"
println "ChildInitAndVisit - calling visit() -> ${iv.visit()}"

v = new ChildVisitOnly()
println "ChildVisitOnly - calling visit() -> ${v.visit()}"
我希望看到:

ChildVisitOnly - calling visit() -> GrandParent init, Parent init, Child visit
作为最后一个println的输出。相反,我看到:

ChildVisitOnly - calling visit() -> GrandParent init, Child visit
这与ChildInitAndVisite类的行为形成对比,与Groovy-I checked 2.3.4的旧版本下的行为不同

这是一个Groovy bug吗?或者我应该做些不同的事情吗?

我相信这就是Groovy的(运行时/动态调度)行为。在运行时,将使用来自
祖父母的
init()
,而不是来自
Parent的
init()

class ChildVisitOnly extends Parent { 

    String visit() { 
        return init() + "Child visit" 
    } 
}
Java方式(编译时调度)使用它的一种方法是在
ChildVisitOnly
类上使用
@CompileStatic

@CompileStatic
class ChildVisitOnly extends Parent { 

    String visit() { 
        return super.init() + "Child visit" 
    } 
}
以上将给出您期望的结果

另一种方法是在
ChildVisitOnly
中显式地使用
init()
this.init()
,而不是
@CompileStatic
来强制使用
init()

class ChildVisitOnly extends Parent { 

    String visit() { 
        return init() + "Child visit" 
    } 
}

这显然偏离了Groovy 2.3.4的行为,但我还没有找到一个关注这一差异的相关问题。我很好奇,看看是否有人能给我指出导致行为改变的缺陷。:)

在我看来,这是一个错误super.init()
必须调用父#init()。

Groovy使用的基于实例的多方法意味着,当考虑父类中的方法调用时,子类中的方法在父类的范围内变得可见,同时处理子类的实例。但是多方法不会覆盖Java意义上的方法。这意味着,ChildVisitOnly中的init方法必须来自父级,而不是祖父母。Groovy根本无法理解,如果您编写
super.init()
,并且不重写init()方法,它就不应该接受init方法声明类的父类