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

pbpqsu0x  于 2023-03-09  发布在  Kotlin
关注(0)|答案(3)|浏览(125)

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

  • 抽象类可以有状态(例如var ...)
  • 一个类可以实现多个接口,但不能实现多个抽象类。

既然Kotlin是一种相当新鲜的语言,我想知道为什么抽象类没有被抛弃?接口似乎是一种更好的工具,几乎不需要抽象类。
详细说明:Kotlin确实支持接口中的具体函数实现,例如:

interface Shiny {

    fun shine(amount : Int)  // abstract function

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

}

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

pengsaosao

pengsaosao1#

抽象类实用的一面是,您可以封装与状态一起工作的实现的一部分,以便它不能在派生类中被重写。
在接口中,只能定义没有支持字段的属性,并且实现类必须重写该属性(使用支持字段或自定义访问器)。
鉴于此,您无法定义以可靠的方式在接口中存储某些状态的逻辑:实现类可能以意想不到的方式覆盖属性。
示例:

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(内部的、受保护的)和final成员,而接口不能(它们只能有私有成员,可以在默认实现中使用),并且它们所有的默认实现都可以在类中被重写。

ffscu2ro

ffscu2ro2#

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

3wabscal

3wabscal3#

我写这个答案也是为了检查我的理解。

  • 抽象类可以具有构造函数、init块和字段/属性,以便它们可以保存状态
  • 接口不能具有上述属性。

使用抽象类可以共享状态,另一方面,使用接口可以共享行为。
例如
想象一下,你有一个形状类,它有一个默认的颜色,对所有形状都是通用的,但是每个形状可以有不同的'面积','周长'或任何其他可能需要的方法的实现,那么最好的工具是抽象类。

相关问题