Kotlin:为什么使用抽象类(相对于接口)?

Kotlin:为什么使用抽象类(相对于接口)?,kotlin,abstract-class,Kotlin,Abstract Class,我知道Kotlin中抽象类和接口之间有两个区别: 抽象类可以有状态(例如,var…) 一个类可以实现多个接口,但不能实现多个抽象类 由于Kotlin是一种相当新的语言,我想知道为什么抽象类没有被放弃?接口似乎是一种高级工具,对抽象类的需求很少 详细说明:Kotlin确实支持接口中的具体功能实现,例如: interface Shiny { fun shine(amount : Int) // abstract function fun reflect(s : String

我知道Kotlin中抽象类和接口之间有两个区别:

  • 抽象类可以有状态(例如,
    var
    …)
  • 一个类可以实现多个接口,但不能实现多个抽象类
由于Kotlin是一种相当新的语言,我想知道为什么抽象类没有被放弃?接口似乎是一种高级工具,对抽象类的需求很少

详细说明:Kotlin确实支持接口中的具体功能实现,例如:

interface Shiny {

    fun shine(amount : Int)  // abstract function

    fun reflect(s : String) { print ("**$s**") }  // concrete function

}

有人能提供一个强有力的实例来说明抽象类的需求吗?

抽象类本质上是为了类的层次结构而存在的。例如,如果抽象父类有一个具体的函数,该函数也是在扩展父类的子类中定义的,那么在某些情况下,有必要调用父类的函数。当您使用接口时,由于类的完全抽象性质,因此不可能这样做。

抽象类的实际一面是,您可以封装与状态一起工作的实现的一部分,这样就不能在派生类中重写它

在接口中,您只能定义没有支持字段的属性,并且实现类必须重写该属性(使用支持字段或自定义访问器)

鉴于此,您无法定义以可靠方式在接口中存储某些状态的逻辑:实现类可能以意外方式重写属性

例如:

interface MyContainer {
    var size: Int

    fun add(item: MyItem) { 
        // ...
        size = size + 1
    }
}
这里,我们为
add
提供了一个默认实现,它增加了
size
。但如果实现类的定义如下所示,它可能会中断:

class MyContainerImpl : MyContainer {
    override val size: Int 
        get() = 0
        set(value) { println("Just ignoring the $value") }
}
相反,抽象类支持这个用例,因此允许您为它们的所有实现提供一些保证和契约:它们可以定义一些状态及其转换,这些状态和转换在派生类中保持不变


除此之外,抽象类可以有非公共API(内部、受保护)和最终成员,而接口不能(它们只能有私有成员,可以在默认实现中使用),它们的所有默认实现都可以在类中重写。

其中一个区别是,如果将其设为接口,则可以将多个接口继承到一个类,但对于抽象类,只能将单个抽象类继承到一个类(超类型列表中仅显示一个类)


快乐编码

这实际上与问“为什么要在java或c#中使用抽象类”或任何其他面向对象语言是一样的。接口上具体功能的支持-不是回答此问题时的状态。Bkotlin很新鲜,可以选择放弃抽象类(与java相比,java必须支持向后兼容性),kotlin在编译到JVM时不会实现任何高开销的东西。由于与Java 6兼容,它不使用Java 8风格的接口默认方法。@LiorBar On I do-这个问题的答案实际上与相同。我不确定我是否理解:Kotlin接口上支持具体的函数实现。我用一个例子详细阐述了我的问题。引用自Kotlin网站“Kotlin中的接口与Java8非常相似。它们可以包含抽象方法的声明,也可以包含方法实现。与抽象类不同的是,接口不能存储状态。它们可以有属性,但这些属性必须是抽象的或提供访问器实现。“除此之外,我认为将接口或抽象类作为对象传递也会有所不同,因为类将具有任意的超类,但我不确定Kotlin中的接口是否如此。事实并非如此:在Kotlin中,如果接口提供默认实现,实现类可以使用
super.f()
调用该实现,请参见@hotkey,这很有趣。为什么Kotlin团队决定以这种方式(您在回答中解释的方式)开发该语言,而不将其标准化为java?JetBrains在2011年公开宣布Kotlin。当时,JSR-355(Java中的lambda表达式和虚拟扩展方法)只是一个早期草案。“除此之外,抽象类可以有非公共和最终成员,而接口不能”-似乎接口可以为具体函数设置
private
修饰符-其余的都是对的:所有接口函数都是开放的,不能是内部的。@LiorBar On,啊,事实上,这些函数可以在默认实现中使用,并且不影响API。谢谢,更新了asnwer。