在前面幾個章節中,詳細的介紹了Kotlin
類的類別中的數據類
、密封類
、接口類
以及枚舉類
。在這個章節中會對Koltin
的抽象類
和內部類
做出一個詳細的講解。若是對上面所提到的類的類別還不是很清晰的,請閱讀個人前幾篇文章。
Kotlin——中級篇(六):數據類(data)、密封類詳解
Kotlin——中級篇(五):枚舉類(Enum)、接口類(Interface)詳解
Kotlin——中級篇(一):類(class)詳解html
- 咱們知道,在實際的開發程序的時候,通常都會寫一個基類,封裝經常使用方法、以及處理一些共有的邏輯,可是程序邏輯是根據每一個類不一樣的功能實現不一樣的代碼。而這個所謂的基類,通常都是一個抽象類。不論是
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
的設計模式中,有一種設計模式叫模板設計模式
,其定義爲:
- 定義一個操做中算法的骨架,而將一些步驟延遲到子類中,模板方法使得子類能夠不改變算法的結構便可重定義該算法的某些特定步驟。
- 通俗點的理解就是 :完成一件事情,有固定的數個步驟,可是每一個步驟根據對象的不一樣,而實現細節不一樣;就能夠在父類中定義一個完成該事情的總方法,按照完成事件須要的步驟去調用其每一個步驟的實現方法。每一個步驟的具體實現,由子類完成。
Kotlin
和Java
是互通的,說明Kotlin
也是支持這種設計模式的。
若是你對Java
中的模板設計模式不是很瞭解的,請參見這篇文章函數
在實際開發中,用到內部類的地方是不少的。好比說:工具
- 對於
Android
開發來講,列表適配器(adapter
)中的ViewHolder
類,就是一個內部類。- 根據後臺開發人員提供的
json
字符串生成的對象中,也包含另一個對象,這也是一個內部類。
上面提到的兩種狀況,是在開發中最多見的。固然,說到內部類,就必須世道另外一個概念嵌套類,所謂的嵌套類:即指一個類能夠嵌套在其餘類中。
例:
class Other{ // 外部類
val numOuther = 1
class Nested { // 嵌套類
fun init(){
println("執行了init方法")
}
}
}
fun main(args: Array<String>) {
Other.Nested().init() // 調用格式爲:外部類.嵌套類().嵌套類方法/屬性
}
複製代碼
輸出結果爲:
執行了init方法
複製代碼
注意:
- 調用嵌套類的屬性或方法的格式爲:
外部類.嵌套類().嵌套類方法/屬性。在調用的時候嵌套類是須要實例化的
。- 嵌套類能夠訪問外部類的屬性和成員
在上面的例子中講解了嵌套類的使用,而內部類和嵌套類仍是有必定的區別的,並且內部類是有特定的關鍵字去聲明的。
聲明一個內部類使用
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() // 調用格式爲:外部類().內部類().內部類方法/屬性
}
複製代碼
注意:
- 調用內部類的屬性或方法的格式爲:
外部類().內部類().內部類方法/屬性。在調用的時候外部類、內部類都是須要實例化的
。- 內部類能夠訪問外部類的屬性和成員
做爲一名
Android
開發者,對匿名內部類都不陌生,由於在開發中,匿名內部類隨處可見。好比說Button
的OnClickListener
,ListView
的單擊、長按事件等都用到了匿名內部類。 通常的使用方式爲定義一個接口,在接口中定義一個方法。
例:
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更像是語法糖。這篇文章是別的大牛詮釋靜態類以及單例實現很好的文章。後面我會出一篇詳細的文章爲你們講解。
在學完本篇博文中,你應該掌握抽象類
的做用,掌握其和普通類
、接口類
、繼承類
的區別所在,瞭解實現抽象類
的意義,或者說在項目中爲何要用抽象類
去編寫一個基類
等。
對於嵌套類
和內部類
而言,知道這二者的區別所在,和熟知他們在項目中用在什麼地方就夠了。對於靜態類
來講,經常使用的實現都是用其去實現一個單例模式。在Koltin
的不像Java
同樣實現不少的工具類,由於Kotlin
中的擴展功能很強大。能夠用擴展去替換掉大部分的工具類。本篇文章主要是展現object
的用法而已,詳細的使用場景和用法會在後續的文章中爲你們奉上。
若是各位大佬看了以後感受還闊以,就請各位大佬隨便star
一下,您的關注是我最大的動力。
個人我的博客:Jetictors
個人github:Jetictors