interface CrudRepo {
fun save()
fun saveAll()
}
interface CustomRepo : CrudRepo {
fun validate()
override fun save() {
validate()
saveAll() // can call saveAll, I need to call save on CrudRepo here
}
}
CrudRepo
具有不保存验证的功能。我决定编写自己的接口,该接口扩展了CrudRepo
并覆盖了save方法。在我自己的save
定义中,我想验证然后在save
上调用CrudRepo
方法。
我应该尝试什么?
答案 0 :(得分:1)
如果您尝试使用super
,则会收到一条错误消息,提示“无法直接访问抽象成员”。这适用于接口和类;您不能在super
上调用无主体抽象方法。这意味着无法编译:
interface CrudRepo {
fun save()
fun saveAll()
}
interface CustomRepo : CrudRepo {
fun validate()
override fun save() {
validate()
super.saveAll()
}
}
但是将CrudRepo界面更改为此:
interface CrudRepo {
fun save()
fun saveAll(){
}
}
确实如此。
如果您想要一个抽象的示例,请转到:
abstract class CrudRepo {
abstract fun save()
abstract fun saveAll()
}
class CustomRepo : CrudRepo() {
override fun saveAll() { }
override fun save() {
super.saveAll()
}
}
您将收到相同的错误消息。这是因为您不能调用方法的未实现版本。另外,让我们看一下继承。
interface CustomRepo : CrudRepo
class MyClass : CustomRepo
表示MyClass
是CrudRepo和CustomRepo的子代。 MyClass() as CustomRepo
和MyClass() as CrudRepo
都将编译。
现在,这对您的问题意味着什么?
从save
的角度来看,CrudRepo
中没有CustomRepo
方法。它尚未实现,因此不能直接调用它。如上所示,调用super.saveAll()
意味着call the saveAll method on my parent
。 super
是一个非常严格的关键字。但是,saveAll()
不会被覆盖。您可以 调用save
,但是您不能在超级接口上调用它,因为超级接口没有带有正文的保存方法。这句话的最后三个词在这里非常重要。由于CrudBody接口中定义的方法没有主体,因此无法调用它。
此外,由于您已经重写了该方法,因此对该方法的任何调用都将导致递归。如果您这样做:
override fun save(){
save()
}
它将反复调用自身,直到崩溃。参见What is a StackOverflowError?。
现在,如果您有实际班级:
class CustomRepoImpl : CustomRepo{
override fun saveAll() {
}
override fun save() {
super.save()
}
override fun validate() {
}
}
注意如何调用super
;现在它将在CustomRepo
中调用super方法。但这不是必需的。
当您在save
中覆盖CustomRepo
时,请记住一件事:您正在覆盖CrudRepo的方法。不再需要任何子类来覆盖它。没有它,我将编译该示例实现。 saveAll
有效(没有super
关键字)的原因是因为它是抽象的,并且没有引用从中调用它的方法。请参阅StackOverflowError链接。如果调用重写的方法,则将调用子类中的方法,除非在super
上调用了该方法。
并且您不能在超类或接口的无体方法上调用super
,因为该语言不知道您要指向什么,因为那里什么也没有。
TL; DR:,您不能调用抽象/无体方法的超级方法。 saveAll
引用方法的第一个实现,如果在子对象中定义,则引用超类。调用save
会导致StackOverflowError。
答案 1 :(得分:0)
我认为Zoes答案包含您需要了解的有关继承或覆盖save
方法的所有信息。如果您的CustomRepo
最初不是接口,则可以使用delegation,例如:
class CustomRepo(private val repo : CrudRepo) : CrudRepo by repo {
fun validate() {}
override fun save() {
validate()
repo.save()
}
}
因此,如果您有CrudRepo
,只需将其包装到CustomRepo
中即可。而已。默认情况下,所有方法都将委派给您的CrudRepo
,如果您不希望自己覆盖需要以不同方式工作的函数。
如果您真的想保留自定义interface
,那么我可能会做以下事情:
interface ValidatedCrudRepo : CrudRepo {
fun validate()
/**
* Ensures that [validate] is called before the actual [save].
*/
override fun save()
}
class CustomRepo(private val repo : CrudRepo) : ValidatedCrudRepo, CrudRepo by repo {
override fun validate() {}
override fun save() {
validate()
repo.save()
}
}
因此,如果有人使用ValidatedCrudRepo
,则可以确保在实际保存之前调用validate并以同样的方式进行记录。