Kotlin——中級篇(七):抽象類(abstract)、內部類(嵌套類)詳解

在前面幾個章節中,詳細的介紹了Kotlin類的類別中的數據類密封類接口類以及枚舉類。在這個章節中會對Koltin抽象類內部類做出一個詳細的講解。若是對上面所提到的類的類別還不是很清晰的,請閱讀個人前幾篇文章。
Kotlin——中級篇(六):數據類(data)、密封類詳解
Kotlin——中級篇(五):枚舉類(Enum)、接口類(Interface)詳解
Kotlin——中級篇(一):類(class)詳解html

目錄

1、抽象類

  • 咱們知道,在實際的開發程序的時候,通常都會寫一個基類,封裝經常使用方法、以及處理一些共有的邏輯,可是程序邏輯是根據每一個類不一樣的功能實現不一樣的代碼。而這個所謂的基類,通常都是一個抽象類。不論是Java仍是Kotlin,實現其抽象類的做用就在於此。那麼什麼是抽象類呢,它是怎麼定義的,它又要怎麼使用呢?

一、抽象類的定義

抽象類,能夠理解爲類定義了一個模板。全部的子類都是根據這個模板是填充本身的代碼。java

1.一、關鍵字git

  • 聲明一個抽象(類或函數)的關鍵字爲:abstract

其中值得注意的是:抽象能夠分爲抽象類、抽象函數、抽象屬性。而一個抽象類和普通類的區別在於抽象類除了能夠有其本身的屬性、構造函數、方法等組成部分,還包含了抽象函數以及抽象屬性。github

例:算法

abstract class Lanauage{
    val TAG = this.javaClass.simpleName  // 自身的屬性
    
    // 自身的函數
    fun test() : Unit{
        // exp
    }
    abstract var name : String           // 抽象屬性
    abstract fun init()                  // 抽象方法
}

/**
 * 抽象類Lanauage的實現類TestAbstarctA
 */
class TestAbstarctA : Lanauage(){

    override var name: String
        get() = "Kotlin"
        set(value) {}

    override fun init() {
        println("我是$name")
    }
}

/**
 * 抽象類Lanauage的實現類TestAbstarctB
 */
class TestAbstarctB : Lanauage(){
    override var name: String
        get() = "Java"
        set(value) {}

    override fun init() {
        println("我是$name")
    }
}

fun main(args: Array<String>) {
    
    // val lanauage = Lanauage() 是錯誤的,由於抽象類不能直接被實例化
    
    val mTestAbstarctA = TestAbstarctA()
    val mTestAbstarctB = TestAbstarctB()

    println(mTestAbstarctA.name)
    mTestAbstarctA.init()

    println(mTestAbstarctB.name)
    mTestAbstarctB.init()
}

輸出結果爲:json

Kotlin
我是Kotlin
Java
我是Java

1.二、小結設計模式

  • 抽象類自己具備普通類特性,以及組成部分。不過值得注意的是,抽象類不能直接被實例化
  • 其抽象了類的子類必須所有重寫帶abstract修飾的屬性和方法。
  • 抽象成員只有定義,沒有實現。都有abstract修飾符修飾。
  • 抽象類是爲其子類定義了一個模板。不一樣是類實現不一樣的功能

二、抽象類的規則

  • Kotlin中的抽象類在頂層定義的時候只能使用public可見性修飾符修飾。
  • 抽象類中能夠定義內部抽象類。
  • 只能繼承一個抽象類。
  • 若要實現抽象類的實例化,須要依靠子類採用向上轉型的方式處理。
  • 抽象類能夠繼承自一個繼承類,即抽象類能夠做爲子類。不過,抽象類建議不用open修飾符修飾,由於能夠覆寫抽象類的父類的函數。

例:ide

open class Base{
    open fun init(){}
}

abstract class Lanauage : Base(){
    val TAG = this.javaClass.simpleName  // 自身的屬性

    // 自身的函數
    fun test() : Unit{
        // exp
    }
    abstract var name : String           // 抽象屬性
    abstract override fun init()         // 覆寫父類的方法
    
    abstract class Name(){}              // 嵌套抽象類,可查看第二節中的嵌套類使用
}

fun main(args: Array<String>) {
    // 若要實現抽象類的實例化,須要依靠子類採用向上轉型的方式處理。
    val mLanauage : Lanauage = TestAbstarctB()
}

三、抽象類的實際應用

  • Java的設計模式中,有一種設計模式叫模板設計模式,其定義爲:
    • 定義一個操做中算法的骨架,而將一些步驟延遲到子類中,模板方法使得子類能夠不改變算法的結構便可重定義該算法的某些特定步驟。
    • 通俗點的理解就是 :完成一件事情,有固定的數個步驟,可是每一個步驟根據對象的不一樣,而實現細節不一樣;就能夠在父類中定義一個完成該事情的總方法,按照完成事件須要的步驟去調用其每一個步驟的實現方法。每一個步驟的具體實現,由子類完成。

KotlinJava是互通的,說明Kotlin也是支持這種設計模式的。
若是你對Java中的模板設計模式不是很瞭解的,請參見這篇文章函數

2、內部類(嵌套類)

在實際開發中,用到內部類的地方是不少的。好比說:工具

  • 對於Android開發來講,列表適配器(adapter)中的ViewHolder類,就是一個內部類。
  • 根據後臺開發人員提供的json字符串生成的對象中,也包含另一個對象,這也是一個內部類。

一、嵌套類

上面提到的兩種狀況,是在開發中最多見的。固然,說到內部類,就必須世道另外一個概念嵌套類,所謂的嵌套類:即指一個類能夠嵌套在其餘類中。

例:

class Other{           // 外部類
    val numOuther = 1

    class Nested {      // 嵌套類
        fun init(){
            println("執行了init方法")
        }
    }
}

fun main(args: Array<String>) {
    Other.Nested().init()      // 調用格式爲:外部類.嵌套類().嵌套類方法/屬性
}

輸出結果爲:

執行了init方法

注意:

  • 調用嵌套類的屬性或方法的格式爲:外部類.嵌套類().嵌套類方法/屬性。在調用的時候嵌套類是須要實例化的
  • 嵌套類不能使用外部類的屬性和成員

二、內部類

在上面的例子中講解了嵌套類的使用,而內部類和嵌套類仍是有必定的區別的,並且內部類是有特定的關鍵字去聲明的。

2.一、關鍵字

聲明一個內部類使用inner關鍵字。
聲明格式:inner class 類名(參數){}

例:

class Other{            // 外部類
    val numOther = 1

    inner class InnerClass{     // 嵌套內部類
        val name = "InnerClass"
        fun init(){
            println("我是內部類")
        }
    }
}

fun main(args: Array<String>) {
   Other().InnerClass().init()  // 調用格式爲:外部類().內部類().內部類方法/屬性
}

注意:

  • 調用內部類的屬性或方法的格式爲:外部類().內部類().內部類方法/屬性。在調用的時候嵌套類是須要實例化的
  • 內部類不能使用外部類的屬性和成員

2.二、匿名內部類

做爲一名Android開發者,對匿名內部類都不陌生,由於在開發中,匿名內部類隨處可見。好比說ButtonOnClickListenerListView的單擊、長按事件等都用到了匿名內部類。
通常的使用方式爲定義一個接口,在接口中定義一個方法。

例:

class Other{
    
    lateinit private var listener : OnClickListener

    fun setOnClickListener(listener: OnClickListener){
        this.listener = listener
    }
    
    fun testListener(){
        listener.onItemClick("我是匿名內部類的測試方法")
    }
}    

interface OnClickListener{
    fun onItemClick(str : String)
}

fun main(args: Array<String>){
    // 測試匿名內部類
    val other = Other()
    other.setOnClickListener(object : OnClickListener{
        override fun onItemClick(str: String) {
            // todo
            println(str)
        }
    })
    other.testListener()
}

輸出結果爲:

我是匿名內部類的測試方法

遺留的問題

在上面實現的匿名內部類是很常規的用法以及寫法。在咱們的實際開發當中也是你們熟知的寫法。可是在咱們實際開發當中,會引入lambda語法糖,讓咱們的項目支持lambda語法,簡化代碼量。在這裏我也是想把用lambda語法實現匿名內部類實現的代碼貼出來,可是考慮到不少朋友不知道lambda語法強大或者對lambda不瞭解,同時考慮到篇幅緣由,故而在個人下一篇博文Kotlin——高級篇(一):Lambda表達式詳解去講解。

三、局部類

所謂局部類,這一點和Java是一致的。即定義在方法(函數)中的類。

例:

class Other{    // 外部類
    val numOther = 1
    
    fun partMethod(){
        var name : String = "partMethod"

        class Part{
            var numPart : Int = 2

            fun test(){
                name = "test"
                numPart = 5
                println("我是局部類中的方法")
            }
        }

        val part = Part()
        println("name = $name \t numPart = " + part.numPart + "\t numOther = numOther")
        part.test()
        println("name = $name \t numPart = " + part.numPart + "\t numOther = numOther")
    }
}

fun main(args: Array<String>) {
    // 測試局部類
    Other().partMethod()
}

輸出結果爲:

name = partMethod    numPart = 2    numOther = 1
我是局部類中的方法
name = test      numPart = 5    numOther = 1

經過上面的實例:咱們能夠看出:

  • 局部類只能在定義該局部類的方法中使用。
  • 定義在實例方法中的局部類能夠訪問外部類的全部變量和方法。但不能修改
  • 局部類中的能夠定義屬性、方法。而且能夠修改局部方法中的變量。

四、靜態類

熟悉Java的朋友都知道Java的靜態類,或者說用static修飾符修飾的類。可是在Kotlin中,是不存在static關鍵字的。那麼咱們怎樣去實現一個靜態類呢?

關於靜態類的使用,以及靜態類的語法。以及Koltin的單例模式實現。因爲篇幅緣由我在這裏就不展現了。有興趣的朋友請參見kotlin中的object更像是語法糖。這篇文章是別的大牛詮釋靜態類以及單例實現很好的文章。後面我會出一篇詳細的文章爲你們講解。

3、總結

在學完本篇博文中,你應該掌握抽象類的做用,掌握其和普通類接口類繼承類的區別所在,瞭解實現抽象類的意義,或者說在項目中爲何要用抽象類去編寫一個基類等。
對於嵌套類內部類而言,知道這二者的區別所在,和熟知他們在項目中用在什麼地方就夠了。對於靜態類來講,經常使用的實現都是用其去實現一個單例模式。在Koltin的不像Java同樣實現不少的工具類,由於Kotlin中的擴展功能很強大。能夠用擴展去替換掉大部分的工具類。本篇文章主要是展現object的用法而已,詳細的使用場景和用法會在後續的文章中爲你們奉上。

源代碼

若是各位大佬看了以後感受還闊以,就請各位大佬隨便star一下,您的關注是我最大的動力。
個人我的博客Jetictors
個人githubJetictors
個人掘金Jetictors

歡迎各位大佬進羣共同研究、探索

QQ羣號:497071402

相關文章
相關標籤/搜索