書接上篇……
之所以將這三個(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 = "男人的頭";
}
}

這是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 = "男人的頭"
}
}

好了,這就是基本的繼承了。
要點(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只支持單繼承

這里又一點(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):

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ò)誤

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

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

這里我要來(lái)說(shuō)一個(gè)容易混淆的地方
也就是上文提到的:
在子類中 無(wú)論是實(shí)現(xiàn)接口,還是繼承父類都是使用的:
那么區(qū)別在于

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

好了就到這,這些東西我只講了個(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)系,看代碼就是了

上圖中首先創(chuàng)建了一個(gè)名為t的KtTest對(duì)象,然后通過(guò)t::func傳給了show方法
show方法中的參數(shù)是一個(gè)名為funcM的參數(shù)名,類型為()->Unit
()->Unit表示一個(gè)返回空的方法。
如果不好理解,可以這么看

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

*注意:如果對(duì)象沒有創(chuàng)建(new),那么不能直接傳方法,至于為什么?對(duì)象都沒有創(chuàng)建,虛擬機(jī)怎么知道該調(diào)用誰(shuí)的方法。
5. 總結(jié)
- kotlin中,繼承需要父類使用
open關(guān)鍵字,子類實(shí)現(xiàn)則需要以override關(guān)鍵字,不能省略 - kotlin中,抽象類與java中幾乎一樣。
- kotlin中,接口與抽像類一樣可以有方法實(shí)現(xiàn),子類繼承可以選擇性覆寫已經(jīng)實(shí)現(xiàn)的方法
- kotlin中,如果子類的上級(jí)存在
兩個(gè)已經(jīng)實(shí)現(xiàn)的相同方法可以通過(guò)super<泛型>.方法名指定使用上級(jí)的方法,但不是必須要寫。 - kotlin中,繼承與接口的實(shí)現(xiàn)都是用的
:表達(dá)式,區(qū)分的方式就是(),也就是子類繼承父類相當(dāng)于創(chuàng)建了一個(gè)父類對(duì)象,然而接口則不需要。 - kotlin中,支持函數(shù)(方法)作為參數(shù)傳遞,使用
::表達(dá)式