【KtAndroid - 7】繼承、抽象類、接口

書接上篇……

之所以將這三個(gè)寫在一起而不與類寫在一起,大概是因?yàn)檫@三者惺惺相惜吧。(類寫完了才發(fā)現(xiàn),如果一個(gè)開一篇文章的話……有劃水的趕腳!嘿嘿)

在面向?qū)ο笾羞@繼承、抽象類、接口三者可是占著不弱的低位哈,可以說(shuō)有了它們,面向?qū)ο蟛啪邆淞遂`魂。

在上篇文章我說(shuō)了類的定義,對(duì)象的創(chuàng)建,其實(shí)都沒什么,但是??!構(gòu)造方法的定義與使用一定要摸清楚。因?yàn)椋谟脩T了java后對(duì)于接下來(lái)的繼承、抽象類、接口難免會(huì)覺得。

1. 繼承

一. 基本繼承

首先來(lái)說(shuō)說(shuō)繼承!

來(lái)一段代碼:

package cn.xinidi.java;

/**
 * @author Gang
 * @Date 2020/4/29
 * @Version 1.0
 */
public class JavaFile {
    public static void main(String[] args) {
        Man man = new Man();
        System.out.println(man.head);
    }
}


class Person{
    String head = "頭";
}

class Man extends Person{
    public Man() {
        this.head = "男人的頭";
    }
}
1.png

這是java中的繼承。

來(lái)看kotlin中的繼承:

package cn.xinidi.kotlin

/**
 * @author Gang
 * @Date 2020/4/29
 * @Version 1.0
 */
class KtFile {
    companion object{
        @JvmStatic
        fun main(args: Array<String>) {
            println("kt:${Man().head}")
        }
    }
}

open class Person {
    var head = "頭"
}

class Man : Person() {
    init {
        head = "男人的頭"
    }
}
2.png

好了,這就是基本的繼承了。

要點(diǎn):java沒什么可說(shuō)的。然鵝,對(duì)于kotlin來(lái)說(shuō),父類 Person 使用了一個(gè)open關(guān)鍵字,以達(dá)到子類可以繼承它。(你也可以試試去掉open)

子類繼承的關(guān)鍵字并不是extends而是一個(gè):,其實(shí)這個(gè):在kotlin中還有其他用法,不要急,馬上會(huì)說(shuō)。

接下來(lái)說(shuō)方法的繼承,子類重寫父類方法:

open class Person {
    var head = "頭"
    open fun jump() {
        println("跳!")
    }
}

class Man : Person() {
    init {
        head = "男人的頭"
    }

    override fun jump(){
        println("男人在跳!")
    }
}

父類方法jump也是用了open來(lái)聲明,該方法可以被繼承重新,但是在子類中我們?cè)?code>jump前加了一個(gè)override。說(shuō)起override,我相信在java中沒少見它吧。

在java中隨你自己的心情寫或者是不寫它,編譯器不會(huì)提醒你的代碼有問(wèn)題。

但是在kotlin中,你必須寫它,不寫就報(bào)錯(cuò),不給糖就搗蛋。

同樣的,重寫父類字段也是通過(guò)override

open class Person {
    open var head = "頭"
    open fun jump() {
        println("跳!")
    }
}

class Man : Person() {
    override var head = "男人的頭"
    /*init {
        head = "男人的頭"
    }*/

    override fun jump() {
        println("男人在跳!")
    }
}

二. 父類的構(gòu)造函數(shù)

如果繼承的父類帶有參數(shù)構(gòu)造函數(shù),那么該怎么繼承呢?

open class Animal(var type: String) {
    ……
}

class Dog(name: String, type: String) : Animal(type) {
    ……
}

這是在子類擁有主構(gòu)造函數(shù)的情況下,如果沒有主構(gòu)造函數(shù),那么次構(gòu)造函數(shù)怎么寫呢?

open class Animal(var type: String) {
    ……
}

class Cat : Animal {
    constructor(name: String, type: String) : super(type) {
        ……
    }

    constructor(name: String, age: Int, type: String) : super(type) {
        ……
    }
}

子類中可使用super調(diào)用父類的方法。

與java一樣,kotlin只支持單繼承

3.png

這里又一點(diǎn)要注意:

子類繼承父類時(shí),不能有跟父類同名的變量,除非父類中該變量為 private,或者在父類中該變量為 open 并且子類是用 override 關(guān)鍵字重寫的。

2. 抽象類

類的繼承說(shuō)完了,那么接下來(lái)就是今天的第二個(gè)豬腳。

與java一樣,抽象類的聲明也是使用abstract

abstract class AbsKtPerson {
    open abstract fun run()
    open abstract fun jump()
}

繼承實(shí)現(xiàn):

4.png

3. 接口

kotlin中的接口也是用interface來(lái)定義

interface InterfacePerson{
    open fun eat()
    open fun speak(){
        println("說(shuō)話!")
    }
}

interface InterfaceTool{
    open fun knife()
}

class Impl : AbsKtPerson(),InterfacePerson,InterfaceTool{
    override fun run() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun jump() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun eat() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun knife() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}

同時(shí)在kotlin中,接口中支持寫方法體,實(shí)現(xiàn)了方法體的方法,子類可以選擇性實(shí)現(xiàn)。

override fun speak() {
    super.speak()
}

如果多個(gè)上級(jí)中存在了相同的已實(shí)現(xiàn)的方法,如:

abstract class AbsKtPerson {
    open abstract fun run()
    open abstract fun jump()
    //在抽象類中實(shí)現(xiàn)了
    open fun speak(){
        println("AbsKtPerson說(shuō)話!")
    }
}

interface InterfacePerson{
    open fun eat()
    //在接口中實(shí)現(xiàn)了
    open fun speak(){
        println("InterfacePerson說(shuō)話!")
    }
}

將會(huì)出現(xiàn)以下錯(cuò)誤

5.png

你可以通過(guò)泛型指定使用其中一個(gè)的super(但是,該super除了某些特定情況下必須由子類調(diào)用父類,其他情況下并不是必須的)。

也就是你可以這樣:

6.png

但是遇到必要調(diào)用的時(shí)候:

7.png

這里我要來(lái)說(shuō)一個(gè)容易混淆的地方

也就是上文提到的:

在子類中 無(wú)論是實(shí)現(xiàn)接口,還是繼承父類都是使用的:

那么區(qū)別在于

8.png

對(duì),就是這個(gè)()。如果是繼承類,只需要在后面加一個(gè)括號(hào)(別傻啊,這括號(hào)是干嘛的?繼承哪塊已經(jīng)說(shuō)了,負(fù)責(zé)將父類需要的參數(shù)傳過(guò)去,如果父類有一個(gè)參數(shù)構(gòu)造函數(shù),那就不能直接打括號(hào)了)

另外還有一種寫法,可以稍微記一下

9.png

好了就到這,這些東西我只講了個(gè)大概,并不是我講了,你看了,就完了。

要自己多寫多練,另外kotlin中的多態(tài)與java中是一樣的!

4. 關(guān)于“::”引用的說(shuō)明

在java中我們可以通過(guò)接口實(shí)現(xiàn)方法回調(diào),特別是在android這一塊使用得較多。

在kotlin有一種寫法,就是將方法作為參數(shù)傳給需要被調(diào)函數(shù)。

……是不是聽起來(lái)有點(diǎn)繞?沒關(guān)系,看代碼就是了

12.png

上圖中首先創(chuàng)建了一個(gè)名為t的KtTest對(duì)象,然后通過(guò)t::func傳給了show方法

show方法中的參數(shù)是一個(gè)名為funcM的參數(shù)名,類型為()->Unit

()->Unit表示一個(gè)返回空的方法。

如果不好理解,可以這么看

13.png

運(yùn)行結(jié)果:

14.png

*注意:如果對(duì)象沒有創(chuàng)建(new),那么不能直接傳方法,至于為什么?對(duì)象都沒有創(chuàng)建,虛擬機(jī)怎么知道該調(diào)用誰(shuí)的方法。

5. 總結(jié)

  1. kotlin中,繼承需要父類使用open關(guān)鍵字,子類實(shí)現(xiàn)則需要以override關(guān)鍵字,不能省略
  2. kotlin中,抽象類與java中幾乎一樣。
  3. kotlin中,接口與抽像類一樣可以有方法實(shí)現(xiàn),子類繼承可以選擇性覆寫已經(jīng)實(shí)現(xiàn)的方法
  4. kotlin中,如果子類的上級(jí)存在兩個(gè)已經(jīng)實(shí)現(xiàn)的相同方法可以通過(guò)super<泛型>.方法名指定使用上級(jí)的方法,但不是必須要寫。
  5. kotlin中,繼承與接口的實(shí)現(xiàn)都是用的:表達(dá)式,區(qū)分的方式就是(),也就是子類繼承父類相當(dāng)于創(chuàng)建了一個(gè)父類對(duì)象,然而接口則不需要。
  6. kotlin中,支持函數(shù)(方法)作為參數(shù)傳遞,使用::表達(dá)式
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容