一、抽象類
- 我們知道挖胃,在實(shí)際的開發(fā)程序的時(shí)候杂靶,一般都會(huì)寫一個(gè)基類,封裝常用方法酱鸭、以及處理一些共有的邏輯吗垮,但是程序邏輯是根據(jù)每個(gè)類不同的功能實(shí)現(xiàn)不同的代碼。而這個(gè)所謂的基類凹髓,一般都是一個(gè)抽象類烁登。不管是
Java
還是Kotlin
,實(shí)現(xiàn)其抽象類的作用就在于此蔚舀。那么什么是抽象類呢饵沧,它是怎么定義的,它又要怎么使用呢赌躺?
1狼牺、抽象類的定義
抽象類,可以理解為類定義了一個(gè)模板礼患。所有的子類都是根據(jù)這個(gè)模板是填充自己的代碼是钥。
1.1、關(guān)鍵字
- 聲明一個(gè)抽象(類或函數(shù))的關(guān)鍵字為:
abstract
其中值得注意的是:抽象可以分為抽象類缅叠、抽象函數(shù)悄泥、抽象屬性。而一個(gè)抽象類和普通類的區(qū)別在于抽象類除了可以有其自己的屬性肤粱、構(gòu)造函數(shù)弹囚、方法等組成部分,還包含了抽象函數(shù)以及抽象屬性狼犯。
例:
abstract class Lanauage{
val TAG = this.javaClass.simpleName // 自身的屬性
// 自身的函數(shù)
fun test() : Unit{
// exp
}
abstract var name : String // 抽象屬性
abstract fun init() // 抽象方法
}
/**
* 抽象類Lanauage的實(shí)現(xiàn)類TestAbstarctA
*/
class TestAbstarctA : Lanauage(){
override var name: String
get() = "Kotlin"
set(value) {}
override fun init() {
println("我是$name")
}
}
/**
* 抽象類Lanauage的實(shí)現(xiàn)類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() 是錯(cuò)誤的余寥,因?yàn)槌橄箢惒荒苤苯颖粚?shí)例化
val mTestAbstarctA = TestAbstarctA()
val mTestAbstarctB = TestAbstarctB()
println(mTestAbstarctA.name)
mTestAbstarctA.init()
println(mTestAbstarctB.name)
mTestAbstarctB.init()
}
輸出結(jié)果為:
Kotlin
我是Kotlin
Java
我是Java
1.2领铐、小結(jié)
- 抽象類本身具有普通類特性,以及組成部分宋舷。不過值得注意的是绪撵,抽象類不能直接被實(shí)例化
- 其抽象了類的子類必須全部重寫帶
abstract
修飾的屬性和方法。- 抽象成員只有定義祝蝠,沒有實(shí)現(xiàn)音诈。都有
abstract
修飾符修飾。- 抽象類是為其子類定義了一個(gè)模板绎狭。不同是類實(shí)現(xiàn)不同的功能
2细溅、抽象類的規(guī)則
- 在
Kotlin
中的抽象類在頂層定義的時(shí)候只能使用public
可見性修飾符修飾。- 抽象類中可以定義內(nèi)部抽象類儡嘶。
- 只能繼承一個(gè)抽象類喇聊。
- 若要實(shí)現(xiàn)抽象類的實(shí)例化,需要依靠子類采用向上轉(zhuǎn)型的方式處理蹦狂。
- 抽象類可以繼承自一個(gè)繼承類誓篱,即抽象類可以作為子類。不過凯楔,抽象類建議不用
open
修飾符修飾窜骄,因?yàn)榭梢愿矊懗橄箢惖母割惖暮瘮?shù)。
例:
open class Base{
open fun init(){}
}
abstract class Lanauage : Base(){
val TAG = this.javaClass.simpleName // 自身的屬性
// 自身的函數(shù)
fun test() : Unit{
// exp
}
abstract var name : String // 抽象屬性
abstract override fun init() // 覆寫父類的方法
abstract class Name(){} // 嵌套抽象類摆屯,可查看第二節(jié)中的嵌套類使用
}
fun main(args: Array<String>) {
// 若要實(shí)現(xiàn)抽象類的實(shí)例化邻遏,需要依靠子類采用向上轉(zhuǎn)型的方式處理。
val mLanauage : Lanauage = TestAbstarctB()
}
3虐骑、抽象類的實(shí)際應(yīng)用
- 在
Java
的設(shè)計(jì)模式中准验,有一種設(shè)計(jì)模式叫模板設(shè)計(jì)模式
,其定義為:
- 定義一個(gè)操作中算法的骨架富弦,而將一些步驟延遲到子類中沟娱,模板方法使得子類可以不改變算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
- 通俗點(diǎn)的理解就是 :完成一件事情腕柜,有固定的數(shù)個(gè)步驟,但是每個(gè)步驟根據(jù)對(duì)象的不同矫废,而實(shí)現(xiàn)細(xì)節(jié)不同盏缤;就可以在父類中定義一個(gè)完成該事情的總方法,按照完成事件需要的步驟去調(diào)用其每個(gè)步驟的實(shí)現(xiàn)方法蓖扑。每個(gè)步驟的具體實(shí)現(xiàn)唉铜,由子類完成。
Kotlin
和Java
是互通的律杠,說明Kotlin
也是支持這種設(shè)計(jì)模式的潭流。
二竞惋、內(nèi)部類(嵌套類)
在實(shí)際開發(fā)中,用到內(nèi)部類的地方是很多的灰嫉。比如說:
- 對(duì)于
Android
開發(fā)來說拆宛,列表適配器(adapter
)中的ViewHolder
類,就是一個(gè)內(nèi)部類讼撒。- 根據(jù)后臺(tái)開發(fā)人員提供的
json
字符串生成的對(duì)象中浑厚,也包含另外一個(gè)對(duì)象,這也是一個(gè)內(nèi)部類根盒。
1钳幅、嵌套類
上面提到的兩種情況,是在開發(fā)中最常見的炎滞。當(dāng)然敢艰,說到內(nèi)部類,就必須世道另一個(gè)概念嵌套類册赛,所謂的嵌套類:即指一個(gè)類可以嵌套在其他類中盖矫。
例:
class Other{ // 外部類
val numOuther = 1
class Nested { // 嵌套類
fun init(){
println("執(zhí)行了init方法")
}
}
}
fun main(args: Array<String>) {
Other.Nested().init() // 調(diào)用格式為:外部類.嵌套類().嵌套類方法/屬性
}
輸出結(jié)果為:
執(zhí)行了init方法
注意:
- 調(diào)用嵌套類的屬性或方法的格式為:
外部類.嵌套類().嵌套類方法/屬性。在調(diào)用的時(shí)候嵌套類是需要實(shí)例化的
击奶。- 嵌套類不能使用外部類的屬性和成員
2辈双、內(nèi)部類
在上面的例子中講解了嵌套類的使用,而內(nèi)部類和嵌套類還是有一定的區(qū)別的柜砾,而且內(nèi)部類是有特定的關(guān)鍵字去聲明的湃望。
2.1、關(guān)鍵字
聲明一個(gè)內(nèi)部類使用
inner
關(guān)鍵字痰驱。
聲明格式:inner class 類名(參數(shù)){}
例:
class Other{ // 外部類
val numOther = 1
inner class InnerClass{ // 嵌套內(nèi)部類
val name = "InnerClass"
fun init(){
println("我是內(nèi)部類")
}
}
}
fun main(args: Array<String>) {
Other().InnerClass().init() // 調(diào)用格式為:外部類().內(nèi)部類().內(nèi)部類方法/屬性
}
注意:
- 調(diào)用內(nèi)部類的屬性或方法的格式為:
外部類().內(nèi)部類().內(nèi)部類方法/屬性证芭。在調(diào)用的時(shí)候嵌套類是需要實(shí)例化的
。- 內(nèi)部類不能使用外部類的屬性和成員
2.2担映、匿名內(nèi)部類
作為一名
Android
開發(fā)者废士,對(duì)匿名內(nèi)部類都不陌生,因?yàn)樵陂_發(fā)中蝇完,匿名內(nèi)部類隨處可見官硝。比如說Button
的OnClickListener
,ListView
的單擊短蜕、長(zhǎng)按事件等都用到了匿名內(nèi)部類氢架。
一般的使用方式為定義一個(gè)接口,在接口中定義一個(gè)方法朋魔。
例:
class Other{
lateinit private var listener : OnClickListener
fun setOnClickListener(listener: OnClickListener){
this.listener = listener
}
fun testListener(){
listener.onItemClick("我是匿名內(nèi)部類的測(cè)試方法")
}
}
interface OnClickListener{
fun onItemClick(str : String)
}
fun main(args: Array<String>){
// 測(cè)試匿名內(nèi)部類
val other = Other()
other.setOnClickListener(object : OnClickListener{
override fun onItemClick(str: String) {
// todo
println(str)
}
})
other.testListener()
}
輸出結(jié)果為:
我是匿名內(nèi)部類的測(cè)試方法
遺留的問題
在上面實(shí)現(xiàn)的匿名內(nèi)部類是很常規(guī)的用法以及寫法岖研。在我們的實(shí)際開發(fā)當(dāng)中也是大家熟知的寫法。但是在我們實(shí)際開發(fā)當(dāng)中警检,會(huì)引入
lambda
語法糖孙援,讓我們的項(xiàng)目支持lambda
語法害淤,簡(jiǎn)化代碼量。在這里我也是想把用lambda
語法實(shí)現(xiàn)匿名內(nèi)部類實(shí)現(xiàn)的代碼貼出來拓售。
3窥摄、局部類
所謂局部類,這一點(diǎn)和
Java
是一致的邻辉。即定義在方法(函數(shù))中的類溪王。
例:
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>) {
// 測(cè)試局部類
Other().partMethod()
}
輸出結(jié)果為:
name = partMethod numPart = 2 numOther = 1
我是局部類中的方法
name = test numPart = 5 numOther = 1
通過上面的實(shí)例:我們可以看出:
- 局部類只能在定義該局部類的方法中使用。
- 定義在實(shí)例方法中的局部類可以訪問外部類的所有變量和方法值骇。但不能修改
- 局部類中的可以定義屬性莹菱、方法。并且可以修改局部方法中的變量吱瘩。
4道伟、靜態(tài)類
熟悉
Java
的朋友都知道Java
的靜態(tài)類,或者說用static
修飾符修飾的類使碾。但是在Kotlin
中蜜徽,是不存在static
關(guān)鍵字的。那么我們?cè)鯓尤?shí)現(xiàn)一個(gè)靜態(tài)類呢票摇?
關(guān)于靜態(tài)類的使用拘鞋,以及靜態(tài)類的語法。以及Koltin
的單例模式實(shí)現(xiàn)矢门。由于篇幅原因我在這里就不展示了盆色。有興趣的朋友請(qǐng)參見kotlin中的object更像是語法糖。這篇文章是別的大牛詮釋靜態(tài)類以及單例實(shí)現(xiàn)很好的文章祟剔。后面我會(huì)出一篇詳細(xì)的文章為大家講解隔躲。
三、總結(jié)
在學(xué)完本篇博文中物延,你應(yīng)該掌握抽象類
的作用宣旱,掌握其和普通類
、接口類
叛薯、繼承類
的區(qū)別所在浑吟,了解實(shí)現(xiàn)抽象類
的意義,或者說在項(xiàng)目中為什么要用抽象類
去編寫一個(gè)基類
等案训。
對(duì)于嵌套類
和內(nèi)部類
而言买置,知道這兩者的區(qū)別所在,和熟知他們?cè)陧?xiàng)目中用在什么地方就夠了强霎。對(duì)于靜態(tài)類
來說,常用的實(shí)現(xiàn)都是用其去實(shí)現(xiàn)一個(gè)單例模式蓉冈。在Koltin
的不像Java
一樣實(shí)現(xiàn)很多的工具類城舞,因?yàn)?code>Kotlin中的擴(kuò)展功能很強(qiáng)大轩触。可以用擴(kuò)展去替換掉大部分的工具類家夺。本篇文章主要是展示object
的用法而已脱柱,詳細(xì)的使用場(chǎng)景和用法會(huì)在后續(xù)的文章中為大家奉上。