美文网首页
kotlin 抽象类(Abstract)和接口(Interfac

kotlin 抽象类(Abstract)和接口(Interfac

作者: Bfmall | 来源:发表于2022-04-21 11:12 被阅读0次

一、抽象类(Abstract)

与Java一样,abstract 关键字用于在Kotlin中声明抽象类。无法实例化抽象类(不能创建抽象类的对象)。但是,您可以从它们中继承子类。

除非您明确使用 abstract 关键字将其抽象,否则抽象类的成员(属性和方法)是非抽象的。让我们举个实例:

abstract class Person {
    
    var age: Int = 40

    fun displaySSN(ssn: Int) {
        println("我的社保号是: $ssn.")
    }

    abstract fun displayJob(description: String)
}

这里,

  • 创建一个抽象类 Person 。您不能创建该类的对象。
  • 该类具有非抽象属性 age和非抽象方法 displaySSN()。如果您需要在子类中覆盖这些成员,则应使用 open 关键字标记它们。
  • 该类具有抽象方法 displayJob()。它没有任何实现,必须在其子类中重写。

注意:抽象类总是开放的。 您不需要显式使用open关键字从它们继承子类。

示例:Kotlin抽象类和方法

abstract class Person(name: String) {

    init {
        println("我的名字是 $name.")
    }

    fun displaySSN(ssn: Int) {
        println("我的社保号是 $ssn.")
    }

    abstract fun displayJob(description: String)
}

class Teacher(name: String): Person(name) {

    override fun displayJob(description: String) {
        println(description)
    }
}

fun main(args: Array<String>) {
    val jack = Teacher("Jack Smith")
    jack.displayJob("我是一名数学老师。")
    jack.displaySSN(23123)
}

运行该程序时,输出为:

我的名字是  Jack Smith.
我是一名数学老师。
我的社保号是 23123.

在这里, Teacher 类派生自抽象类 Person

Teacher 类的对象 jack 被实例化。在创建主构造函数时,我们将“ Jack Smith”作为参数传递给它。这将执行 Person 类的初始化块。

然后,使用Jack对象调用displayJob()方法。 请注意,displayJob()方法在基类中被声明为抽象的,并在派生类中被覆盖。
最后,使用Jack对象调用displaySSN()方法。 该方法是非抽象的,在 Person 类中声明(而不是在 Teacher 类中声明)。

二、 接口(Interface)

Kotlin接口类似于Java 8中的接口。它们可以包含抽象方法的定义以及非抽象方法的实现。但是,它们不能包含任何状态。

也就是说,接口可能有属性,但它必须是抽象的或者必须提供访问器实现。

推荐阅读: Kotlin 抽象类

Kotlin中的抽象类与接口相似,但有一个重要区别。抽象类的属性不是必须抽象的或提供访问器实现的。

如何定义接口?

关键字interface用于在Kotlin中定义接口。例如,

interface MyInterface {

    var test: String   //抽象属性

    fun foo()          //抽象方法
    fun hello() = "Hello there" //具有默认实现的方法
}

这里,

  • 创建接口 MyInterface。
  • 该接口有一个抽象属性 test 和一个抽象方法 foo()。
  • 该接口还具有非抽象方法 hello()。

如何实现接口?

这是类或对象如何实现接口的方法:

interface MyInterface {

    val test: Int   //抽象属性
    fun foo() : String   //抽象方法(返回字符串)
    fun hello() {   //具有默认实现的方法
        // body (optional)
    }
}

class InterfaceImp : MyInterface {

    override val test: Int = 25
    override fun foo() = "Lol"

    //其他代码
}

在这里,InterfaceImp 类实现了 MyInterface 接口。

该类重写接口的抽象成员(test属性 和 foo()方法)。

示例:接口如何工作?

interface MyInterface {

    val test: Int

    fun foo() : String

    fun hello() {
        println("你好,伙计!")
    }
}

class InterfaceImp : MyInterface {

    override val test: Int = 25
    override fun foo() = "Lol"

}

fun main(args: Array<String>) {
    val obj = InterfaceImp()

    println("test = ${obj.test}")
    print("调用 hello(): ")

    obj.hello()

    print("调用和打印 foo(): ")
    println(obj.foo())
}

运行该程序时,输出为:

test = 25
调用 hello(): 你好,伙计!
调用和打印 foo(): Lol

如前面说讲,接口还可以具有提供访问器实现的属性。例如,

interface MyInterface {

    //带实现的属性
    val prop: Int
        get() = 23
}

class InterfaceImp : MyInterface {
    //类主体
}

fun main(args: Array<String>) {
    val obj = InterfaceImp()

    println(obj.prop)
}

运行该程序时,输出为:

23

这里,prop 不是抽象的,但是它在接口中是有效的,因为它提供了访问器的实现。

但是,您不能在接口内部执行类似 val prop:Int = 23 的操作。

在一个类中实现两个或多个接口

Kotlin不允许真正的多重继承。但是,可以在一个类中实现两个或多个接口。例如,

interface A {

    fun callMe() {
        println("来自接口A")
    }
}

interface B  {
    fun callMeToo() {
        println("来自接口B")
    }
}

//实现两个接口A和B
class Child: A, B

fun main(args: Array<String>) {
    val obj = Child()

    obj.callMe()
    obj.callMeToo()
}

运行该程序时,输出为:

来自接口A
来自接口B

解决重写冲突(多接口)
假设两个接口(A和B)具有相同名称的非抽象方法(假设callMe()方法)。您在一个类中实现了这两个接口(假设C)。 现在,如果使用 C 类的对象调用callMe()方法,则编译器将引发错误。 例如

interface A {

    fun callMe() {
        println("接口 A")
    }
}

interface B  {
    fun callMe() {
        println("接口 B")
    }
}

class Child: A, B 

fun main(args: Array<String>) {
    val obj = Child()

    obj.callMe()
}

这是抛出的错误:

Error:(14, 1) Kotlin: Class 'C' must override public open fun callMe(): Unit defined in A because it inherits multiple interface methods of it

要解决此问题,您需要提供自己的实现。这是如何做:

interface A {

    fun callMe() {
        println("接口 A")
    }
}

interface B  {
    fun callMe() {
        println("接口 B")
    }
}

class C: A, B {
    override fun callMe() {
        super<A>.callMe()
        super<B>.callMe()
    }
}

fun main(args: Array<String>) {
    val obj = C()

    obj.callMe()
}

现在,当您运行程序时,输出将是:

接口  A
接口  B

这里,在 C 类中提供了callMe()方法的显式实现。

class C: A, B {
    override fun callMe() {
        super<A>.callMe()
        super<B>.callMe()
    }
}

语句 super<A>.callMe()调用类A的callMe()方法。类似地,super<B>.callMe()调用类B的callMe()方法。

相关文章

网友评论

      本文标题:kotlin 抽象类(Abstract)和接口(Interfac

      本文链接:https://www.haomeiwen.com/subject/nbbvertx.html