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


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

目錄

一、抽象類

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

1、抽象類的定義

抽象類,可以理解為類定義了一個模板。所有的子類都是根據這個模板是填充自己的代碼。

1.1、關鍵字

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

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

例:

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()
}

輸出結果為:

Kotlin
我是Kotlin
Java
我是Java

1.2、小結

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

2、抽象類的規則

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

例:

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()
}

3、抽象類的實際應用

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

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

二、內部類(嵌套類)

在實際開發中,用到內部類的地方是很多的。比如說:

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

1、嵌套類

上面提到的兩種情況,是在開發中最常見的。當然,說到內部類,就必須世道另一個概念嵌套類,所謂的嵌套類:即指一個類可以嵌套在其他類中。

例:

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

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

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

輸出結果為:

執行了init方法

注意:

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

2、內部類

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

2.1、關鍵字

聲明一個內部類使用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.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表達式詳解去講解。

3、局部類

所謂局部類,這一點和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

通過上面的實例:我們可以看出:

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

4、靜態類

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

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

三、總結

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

源代碼

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

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

QQ群號:497071402


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM