Kotlin基礎(chǔ)-類和對象

一停撞、類定義

Kotlin 類可以包含:構(gòu)造函數(shù)和初始化代碼塊县踢、函數(shù)转绷、屬性、內(nèi)部類硼啤、對象聲明议经。
Kotlin 中使用關(guān)鍵字 class 聲明類,后面緊跟類名:

//Kotlin 中的類可以有一個(gè) 主構(gòu)造器谴返,以及一個(gè)或多個(gè)次構(gòu)造器煞肾,主構(gòu)造器是類頭部的一部分,位于類名稱之后:
class Person constructor(firstName: String){  
    var name: String = ……
    var url: String = ……
    
    //Kotlin 中類不能有字段嗓袱。提供了 Backing Fields(后端變量) 機(jī)制,備用字段使用field關(guān)鍵字聲明,field 關(guān)鍵詞只能用于屬性的訪問器
    var num: Int = 100
        get() = field                // 后端變量
        set(value) {
            if (value < 10) {       // 如果傳入的值小于 10 返回該值
                field = value
            } else {
                field = -1         // 如果傳入的值大于等于 10 返回 -1
            }
        }

    //非空屬性必須在定義的時(shí)候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關(guān)鍵字描述屬性:
    lateinit var subject: TestSubject
    
    //次構(gòu)造函數(shù)
    constructor(parent: Person) {
         // 初始化...
    }
     constructor (name: String, age:Int) : this(name) {
        // 初始化...
    }

    init {
        //初始化代碼
    }

    //在類中定義成員函數(shù)
    fun foo() { 
        print("Foo") 
    }
}


// 創(chuàng)建對象籍救,Kotlin 中沒有 new 關(guān)鍵字
val person = Person() 
//使用屬性,只要用名稱引用它即可渠抹; 使用 . 號來引用
person.name           
person.url

我們也可以定義一個(gè)空類:

class Empty
1蝙昙、類的屬性
屬性定義

類的屬性可以用關(guān)鍵字 var 聲明為可變的,
否則使用只讀關(guān)鍵字 val 聲明為不可變梧却。

getter 和 setter

屬性聲明的完整語法:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

getter 和 setter 都是可選
如果屬性類型可以從初始化語句或者類的成員函數(shù)中推斷出來奇颠,那就可以省去類型,val不允許設(shè)置setter函數(shù)放航,因?yàn)樗侵蛔x的烈拒。

2、主次構(gòu)造器
  1. 主構(gòu)造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中荆几,初始化代碼段使用 init 關(guān)鍵字作為前綴吓妆;
  2. 如果構(gòu)造器有注解,或者有可見度修飾符伴郁,這時(shí)constructor關(guān)鍵字是必須的耿战,注解和修飾符要放在它之前;
  3. 次構(gòu)造函數(shù):類也可以有二級構(gòu)造函數(shù)焊傅,需要加前綴 constructor剂陡;
  4. 如果類有主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)都要狐胎,或直接或間接通過另一個(gè)次構(gòu)造函數(shù)代理主構(gòu)造函數(shù)鸭栖。在同一個(gè)類中代理另一個(gè)構(gòu)造函數(shù)使用 this 關(guān)鍵字;
  5. 如果一個(gè)非抽象類沒有聲明構(gòu)造函數(shù)(主構(gòu)造函數(shù)或次構(gòu)造函數(shù)),它會產(chǎn)生一個(gè)沒有參數(shù)的構(gòu)造函數(shù)握巢。構(gòu)造函數(shù)是 public 晕鹊。如果你不想你的類有公共的構(gòu)造函數(shù),你就得聲明一個(gè)空的主構(gòu)造函數(shù):
class Person constructor(firstName: String) {
    init {
        println("FirstName is $firstName")
    }

    //第3 類也可以有二級構(gòu)造函數(shù)暴浦,需要加前綴 constructor:
    constructor(parent: Person) {
        parent.children.add(this) 
    }

    //第4
    constructor (name: String, age:Int) : this(name) {
            // 初始化...
    }

    //第5
    class DontCreateMe private constructor () {
    }
}

主構(gòu)造函數(shù)-->init代碼塊-->次構(gòu)造函數(shù)

二溅话、類的修飾符

類的修飾符包括 classModifier 和_accessModifier_:
classModifier: 類屬性修飾符,標(biāo)示類本身特性歌焦。
abstract    // 抽象類  
final       // 類不可繼承飞几,默認(rèn)屬性
enum        // 枚舉類
open        // 類可繼承,類默認(rèn)是final的
annotation  // 注解類
accessModifier: 訪問權(quán)限修飾符
private    // 僅在同一個(gè)文件中可見
protected  // 同一個(gè)文件中或子類可見
public     // 所有調(diào)用的地方都可見
internal   // 同一個(gè)模塊中可見

三独撇、抽象類

抽象是面向?qū)ο缶幊痰奶卣髦恍寄惐旧恚蝾愔械牟糠殖蓡T纷铣,都可以聲明為abstract的卵史。抽象成員在類中不存在具體的實(shí)現(xiàn)。
注意:無需對抽象類或抽象成員標(biāo)注open注解搜立。

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

abstract class Derived : Base() {
    override abstract fun f()
}

四以躯、嵌套類

我們可以把類嵌套在其他類中,看以下實(shí)例:

class Outer {                  // 外部類
    private val bar: Int = 1
    class Nested {             // 嵌套類
        fun foo() = 2
    }
}

fun main(args: Array<String>) {
    val demo = Outer.Nested().foo() // 調(diào)用格式:外部類.嵌套類.嵌套類方法/屬性
    println(demo)    // == 2
}

kotlin 嵌套類相當(dāng)于 java 的靜態(tài)內(nèi)部類(有static );
kotlin 內(nèi)部類則對應(yīng)于 java 的非靜態(tài)內(nèi)部類(無 static)

五啄踊、內(nèi)部類

內(nèi)部類使用 inner 關(guān)鍵字來表示寸潦。
內(nèi)部類會帶有一個(gè)對外部類的對象的引用,所以內(nèi)部類可以訪問外部類成員屬性和成員函數(shù)社痛。

class Outer {
    private val bar: Int = 1
    var v = "成員屬性"
    /**嵌套內(nèi)部類**/
    inner class Inner {
        fun foo() = bar  // 訪問外部類成員
        fun innerTest() {
            var o = this@Outer //獲取外部類的成員變量
            println("內(nèi)部類可以引用外部類的成員见转,例如:" + o.v)
        }
    }
}

fun main(args: Array<String>) {
    val demo = Outer().Inner().foo()
    println(demo) //   1
    val demo2 = Outer().Inner().innerTest()   
    println(demo2)   // 內(nèi)部類可以引用外部類的成員,例如:成員屬性
}

為了消除歧義蒜哀,要訪問來自外部作用域的 this斩箫,我們使用this@label吏砂,其中 @label 是一個(gè) 代指 this 來源的標(biāo)簽。

六乘客、匿名內(nèi)部類

kotlin 中:用對象表達(dá)式取代了匿名內(nèi)部類;
對象表達(dá)式用 object : 開頭狐血,后面是要實(shí)現(xiàn)/繼承的父類/父接口。如果沒有父類/父接口易核,則只需要 object 即可:

var myobject = object {
    init {
        println("init called")
    }
    //實(shí)現(xiàn)方法
}

//如果它需要實(shí)現(xiàn)多個(gè)接口或父類匈织,用逗號分隔
var myobject = object: MyInterface, MyAbstractClass() {
    override fun print(i: Int) {
        println("i = $i")
    }
}
class Test {
    var v = "成員屬性"

    fun setInterFace(test: TestInterFace) {
        test.test()
    }
}

/**
 * 定義接口
 */
interface TestInterFace {
    fun test()
}

fun main(args: Array<String>) {
    var test = Test()

    /**
     * 采用對象表達(dá)式來創(chuàng)建接口對象,即匿名內(nèi)部類的實(shí)例牡直。
     */
    test.setInterFace(object : TestInterFace {
        override fun test() {
            println("對象表達(dá)式創(chuàng)建匿名內(nèi)部類的實(shí)例")
        }
    })
}
對象表達(dá)式 vs lambda 表達(dá)式

在 kotlin 中缀匕,如果對象表達(dá)式實(shí)現(xiàn)的是一個(gè)函數(shù)式接口(該接口只有一個(gè)抽象方法),我們可以將它轉(zhuǎn)換成 lambda 表達(dá)式碰逸。

 fun setInterFace(test: TestInterFace) {
        test.test()
}

 fun setInterFace{
        test.test()
}

七乡小、數(shù)據(jù)類

Kotlin 可以創(chuàng)建一個(gè)只包含數(shù)據(jù)的類,關(guān)鍵字為 data:

data class User(val name: String, val age: Int)

編譯器會自動的從主構(gòu)造函數(shù)中根據(jù)所有聲明的屬性提取以下函數(shù):

equals() / hashCode()
toString() 格式如 "User(name=John, age=42)"
componentN() functions 對應(yīng)于屬性饵史,按聲明順序排列
copy() 函數(shù)

如果這些函數(shù)在類中已經(jīng)被明確定義了满钟,或者從超類中繼承而來,就不再會生成胳喷。
為了保證生成代碼的一致性以及有意義湃番,數(shù)據(jù)類需要滿足以下條件:

  • 主構(gòu)造函數(shù)至少包含一個(gè)參數(shù)。
  • 所有的主構(gòu)造函數(shù)的參數(shù)必須標(biāo)識為val 或者 var ;
  • 數(shù)據(jù)類不可以聲明為 abstract, open, sealed 或者 inner;
  • 數(shù)據(jù)類不能繼承其他類 (但是可以實(shí)現(xiàn)接口)吭露。
標(biāo)準(zhǔn)數(shù)據(jù)類

標(biāo)準(zhǔn)庫提供了 Pair 和 Triple 吠撮。在大多數(shù)情形中,命名數(shù)據(jù)類是更好的設(shè)計(jì)選擇奴饮,因?yàn)檫@樣代碼可讀性更強(qiáng)而且提供了有意義的名字和屬性。

八择浊、密封類

密封類用來表示受限的類繼承結(jié)構(gòu):當(dāng)一個(gè)值為有限幾種的類型, 而不能有任何其他類型時(shí)戴卜。
在某種意義上,他們是枚舉類的擴(kuò)展:枚舉類型的值集合 也是受限的琢岩,但每個(gè)枚舉常量只存在一個(gè)實(shí)例投剥,而密封類的一個(gè)子類可以有可包含狀態(tài)的多個(gè)實(shí)例。
聲明一個(gè)密封類担孔,使用 sealed 修飾類江锨,密封類可以有子類,但是所有的子類都必須要內(nèi)嵌在密封類中糕篇。
sealed 不能修飾 interface ,abstract class(會報(bào) warning,但是不會出現(xiàn)編譯錯誤)

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}

使用密封類的關(guān)鍵好處在于使用 when 表達(dá)式 的時(shí)候啄育,如果能夠 驗(yàn)證語句覆蓋了所有情況,就不需要為該語句再添加一個(gè) else 子句了拌消。

九挑豌、枚舉類

枚舉類最基本的用法是實(shí)現(xiàn)一個(gè)類型安全的枚舉。
枚舉常量用逗號分隔,每個(gè)枚舉常量都是一個(gè)對象。

enum class Color{
    RED,BLACK,BLUE,GREEN,WHITE
}

枚舉還支持以聲明自己的匿名類及相應(yīng)的方法氓英、以及覆蓋基類的方法侯勉。

enum class ProtocolState {
    WAITING {
        override fun signal() = TALKING
    },

    TALKING {
        override fun signal() = WAITING
    };

    abstract fun signal(): ProtocolState
}

使用枚舉常量
Kotlin 中的枚舉類具有合成方法,允許遍歷定義的枚舉常量铝阐,并通過其名稱獲取枚舉常數(shù)址貌。

EnumClass.valueOf(value: String): EnumClass  // 轉(zhuǎn)換指定 name 為枚舉值,若未匹配成功徘键,會拋出IllegalArgumentException
EnumClass.values(): Array<EnumClass>        // 以數(shù)組的形式练对,返回枚舉值

獲取枚舉相關(guān)信息:

val name: String //獲取枚舉名稱
val ordinal: Int //獲取枚舉值在所有枚舉數(shù)組中定義的順序
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市啊鸭,隨后出現(xiàn)的幾起案子锹淌,更是在濱河造成了極大的恐慌,老刑警劉巖赠制,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赂摆,死亡現(xiàn)場離奇詭異,居然都是意外死亡钟些,警方通過查閱死者的電腦和手機(jī)烟号,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來政恍,“玉大人汪拥,你說我怎么就攤上這事「莺模” “怎么了迫筑?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宗弯。 經(jīng)常有香客問我脯燃,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮由驹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逝嚎。我一直安慰自己,他們只是感情好详恼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布补君。 她就那樣靜靜地躺著,像睡著了一般昧互。 火紅的嫁衣襯著肌膚如雪赚哗。 梳的紋絲不亂的頭發(fā)上她紫,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音屿储,去河邊找鬼贿讹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛够掠,可吹牛的內(nèi)容都是我干的民褂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼疯潭,長吁一口氣:“原來是場噩夢啊……” “哼赊堪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起竖哩,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤哭廉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后相叁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遵绰,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年增淹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椿访。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虑润,死狀恐怖成玫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拳喻,我是刑警寧澤哭当,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站冗澈,受9級特大地震影響钦勘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渗柿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一个盆、第九天 我趴在偏房一處隱蔽的房頂上張望脖岛。 院中可真熱鬧朵栖,春花似錦、人聲如沸柴梆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绍在。三九已至门扇,卻和暖如春雹有,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背臼寄。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工霸奕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吉拳。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓质帅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親留攒。 傳聞我的和親對象是個(gè)殘疾皇子煤惩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容