Kotlin继承

继承是面向对象编程语言的一个重要特征。 继承允许将类(或基类或父类)的特性继承到新类(或派生类或子类)。

主类称为超类(或父类),继承超类的类称为子类(或子类)。 子类包含超类的特性以及它自己的特性。

当两个或多个类具有相同的属性时,这就引入继承的概念。 继承用于提高代码可重用性。 派生类只有一个基类,但可以有多个接口,而基类可能有一个或多个派生类。

在Kotlin中,派生类在类头中使用冒号(:)操作符来继承基类(在派生类名或构造函数之后)。如下代码所示 -

// 声明一个基类
open class Base(p: Int){  

}

// 声明一个继承自 Base 类(也称为基类)的子类:Derived
class Derived(p: Int) : Base(p){  

}

假设有两个不同的类:ProgrammerSalesman,它们具有公共属性nameagesalary以及它们各自的方法:functionalitiesdoProgram()fieldWork()。 继承的特性允许继承包含公共特性的(Employee基类)。

open class Employee(name: String, age: Int, salary: Float) {  
    // code of employee  
}  

class Programmer(name: String, age: Int, salary: Float): Employee(name,age,salary) {  
    // code of programmer  
}  

class Salesman(name: String, age: Int, salary: Float): Employee(name,age,salary) {  
    // code of salesman  
}

所有Kotlin类都有一个共同的超类Any,它是没有明确指定超类时使用的默认超类。

例如,类Example是隐式继承Any类的,即使没有明确写上。

class Example

Kotlin open关键字

由于Kotlin类默认为final,因此不能简单地继承它们。在类之前使用open关键字来为其它类继承这个类。

示例:

open class Example{  
// I can now be extended!  
}

Kotlin继承类中的字段

当继承一个类来派生类时,所有的字段和函数都是继承的。 可以在派生类中使用这些字段和函数。

示例:

open class Base{
    val x = 10
}
class Derived: Base() {
    fun foo() {
        println("x is equal to " + x)
    }
}
fun main(args: Array<String>) {
    val derived = Derived()
    derived.foo()
}

执行上面示例代码,得到以下结果 -

x is equal to 10

Kotlin从类继承方法

open class Bird {
    fun fly() {
        println("flying...")
    }
}
class Duck: Bird() {
    fun swim() {
        println("swimming...")
    }
}
fun main(args: Array<String>) {
    val duck = Duck()
    duck.fly()
    duck.swim()
}

执行上面示例代码,得到以下结果 -

flying...
swimming...

Kotlin继承示例

在这里,声明一个类Employee是超类,ProgrammerSalesman是它的子类。 子类继承属性:name, agesalary 以及包含子类自身的函数,如:doProgram()fieldWork()

open class Employee(name: String, age: Int, salary: Float) {
    init {
        println("Name is $name.")
        println("Age is $age")
        println("Salary is $salary")
    }
}
class Programmer(name: String, age: Int, salary: Float):Employee(name,age,salary){
    fun doProgram() {
        println("programming is my passion.")
    }
}
class Salesman(name: String, age: Int, salary: Float):Employee(name,age,salary){
    fun fieldWork() {
        println("travelling is my hobby.")
    }
}
fun main(args: Array<String>){
    val obj1 = Programmer("Maxsu", 25, 40000f)
    obj1.doProgram()
    val obj2 = Salesman("Ajax", 24, 30000f)
    obj2.fieldWork()
}

执行上面示例代码,得到以下结果 -

Name is Maxsu.
Age is 25
Salary is 40000.0
programming is my passion.
Name is Ajax.
Age is 24
Salary is 30000.0
travelling is my hobby.

Kotlin继承和主要构造函数

如果基类和派生类都具有主构造函数,则参数在基类的主构造函数中初始化。 在上面的继承示例中,所有类都包含三个参数:nameagesalary,所有这些参数都在基类的主构造函数中初始化。

当基类和派生类在主构造函数中包含不同数量的参数时,基类参数将从派生类对象初始化。

示例代码

open class Employee(name: String,salary: Float) {
    init {
        println("姓名:$name.")
        println("薪水:$salary")
    }
}
class Programmer(name: String, dept: String, salary: Float):Employee(name,salary){
    init {
        println("$name 所在部门:$dept ,薪水为:$salary.")
    }
    fun doProgram() {
        println("编程我有激情.")

    }
}
class Salesman(name: String, dept: String, salary: Float):Employee(name,salary){
    init {
        println("$name 所在部门:$dept ,薪水为:$salary.")
    }
    fun fieldWork() {
        println("我的爱好是:旅游.")

    }
}
fun main(args: Array<String>){
    val obj1 = Programmer("Susen", "技术部", 40000f)
    obj1.doProgram()
    println()
    val obj2 = Salesman("Ajax", "市场部", 30000f)
    obj2.fieldWork()
}

执行上面示例代码,得到以下结果 -

姓名:Susen.
薪水:40000.0
Susen 所在部门:技术部 ,薪水为:40000.0.
编程我有激情.

姓名:Ajax.
薪水:30000.0
Ajax 所在部门:市场部 ,薪水为:30000.0.
我的爱好是:旅游.

当创建派生类的对象时,它首先调用超类并执行基类的init块,然后执行它自己的init块。

Kotlin继承和辅助构造函数

如果派生类不包含任何主构造函数,则需要使用super关键字从派生类调用基类辅助构造函数。

示例:

open class Patent {

    constructor(name: String, id: Int) {
        println("执行超类构造函数: $id , $name ")
    }
}

class Child: Patent {

    constructor(name: String, id: Int, dept: String): super(name, id) {
        print("使用属性执行子类构造函数:$name, $id, $dept")
    }
}
fun main(args: Array<String>) {
    val child = Child("Maxsu",10010, "技术部")
}

执行上面示例代码,得到以下结果 -

执行超类构造函数: 10010 , Maxsu 
使用属性执行子类构造函数:Maxsu, 10010, 技术部

在上面的示例中,当创建Child类的对象时,它调用其构造函数并使用值:“Maxsu”,“10010”和“技术部”初始化其参数。 同时,Child类构造函数使用具有nameid值的super关键字调用超类的构造函数。 由于super关键字的存在,超类构造函数的主体首先执行并返回到Child类构造函数。

Kotlin方法覆盖

方法覆盖意味着将super(parent)类的方法的特定实现提供到子类(子)类中。

换句话说,当子类重新定义或修改其超类的方法为子类时,它被称为方法覆盖。 方法覆盖只能在继承中实现。

Kotlin方法覆盖的规则

  • 父类及要覆盖的方法或属性必须是open的(非final)。
  • 基类和派生类的方法名必须相同。
  • 方法必须具有与基类相同的参数。

没有覆盖的继承示例

open class Bird {
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {

}
class Duck: Bird() {

}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    val d = Duck()
    d.fly()
}

执行上面示例代码,得到以下结果 -

Bird is flying...
Bird is flying...

在上面的例子中,一个没有覆盖基类方法的程序出现派生类ParrotDuck类执行相同的操作。 为了克服这个问题,使用方法覆盖这个概念。

Kotlin方法覆盖的示例

在此示例中,子类ParrotDuck中覆盖父类Bird的方法fly()。 要覆盖父类的方法,必须将要覆盖的父类及方法声明为open。 同时,在子类中重写的方法必须以override关键字开头。

open class Bird {
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override fun fly() {
        println("Parrot is flying...")
    }
}
class Duck: Bird() {
    override fun fly() {
        println("Duck is flying...")
    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    val d = Duck()
    d.fly()
}

执行上面示例代码,得到以下结果 -

Parrot is flying...
Duck is flying...

Kotlin属性覆盖的示例

超类的属性也可以在子类中覆盖,这个实现类似于方法。 在子类ParrotDuck中重写并修改Bird类的color属性。

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override var color = "绿色"
    override fun fly() {
        println("Parrot is flying...")
    }
}
class Duck: Bird() {
    override var color = "花色"
    override fun fly() {
        println("Duck is flying...")
    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)
    val d = Duck()
    d.fly()
    println(d.color)
}

执行上面示例代码,得到以下结果 -

Parrot is flying...
绿色
Duck is flying...
花色

可以在继承中使用var属性覆盖val属性,但反之亦然。

Kotlin超类实现

派生类也可以使用super关键字调用超类方法和属性。

例如:

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
class Parrot: Bird() {
    override var color = "绿色"
    override fun fly() {
        super.fly()
        println("Parrot is flying...")
    }
}

fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)

}

执行上面示例代码,得到以下结果 -

Bird is flying...
Parrot is flying...
绿色

Kotlin多类实现

在Kotlin中,派生类在尖括号中使用超类型名称,即,super <Base>,当它实现多个类中提供的相同函数名时。

例如,派生类Parrot扩展超类Bird并实现相同的Duck接口函数fly()。 要调用每个类和接口的特定方法,必须在尖括号中提到超类型名称为super <Bird>.fly()super <Duck>.fly()

open class Bird {
    open var color = "黑色"
    open fun fly() {
        println("Bird is flying...")
    }
}
interface Duck {
    fun fly() {
        println("Duck is flying...")
    }
}
class Parrot: Bird(),Duck {
    override var color = "绿色"
    override fun fly() {
        super<Bird>.fly()
        super<Duck>.fly()
        println("Parrot is flying...")

    }
}
fun main(args: Array<String>) {
    val p = Parrot()
    p.fly()
    println(p.color)

}

执行上面示例代码,得到以下结果 -

Bird is flying...
Duck is flying...
Parrot is flying...
绿色

上一篇:Kotlin可见性修饰符

下一篇:Kotlin抽象类

关注微信小程序
程序员编程王-随时随地学编程

扫描二维码
程序员编程王

扫一扫关注最新编程教程