android鞏固-kotlin第二篇

類和對(duì)象

/* -------------- 類和對(duì)象 -------------- */
/**
Kotlin 類可以包含:構(gòu)造函數(shù)和初始化代碼塊、函數(shù)倚评、屬性城瞎、內(nèi)部類埂蕊、對(duì)象聲明滞谢。
class Runoob {  // 類名為 Runoob
// 大括號(hào)內(nèi)是類體構(gòu)成
}

聲明空類
class Empty

成員函數(shù)
class Runoob {
fun foo(){}
}

類的屬性
class Runoob {
var name:String
var url:String
var city:String
}

實(shí)例的創(chuàng)建
val site = Runoob()
屬性的引用
site.name="zzz"
site.url="action.call"

構(gòu)造方法
class Person constructor(firstName:String){}
如果主構(gòu)造器沒有任何注解髓迎,也沒有任何可見度修飾符硅瞧,那么constructor關(guān)鍵字可以省略偏瓤。
class Person(firstName:String){}

getter 和 setter

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

getter 和 setter 都是可選

如果屬性類型可以從初始化語句或者類的成員函數(shù)中推斷出來杀怠,那就可以省去類型,val不允許設(shè)置setter函數(shù)厅克,因?yàn)樗侵蛔x的赔退。

var allByDefault: Int? // 錯(cuò)誤: 需要一個(gè)初始化語句, 默認(rèn)實(shí)現(xiàn)了 getter 和 setter 方法
var initialized = 1    // 類型為 Int, 默認(rèn)實(shí)現(xiàn)了 getter 和 setter
val simple: Int?       // 類型為 Int ,默認(rèn)實(shí)現(xiàn) getter 证舟,但必須在構(gòu)造函數(shù)中初始化
val inferredType = 1   // 類型為 Int 類型,默認(rèn)實(shí)現(xiàn) getter
 */

class Person {
    var lastName: String = "zhang"
        get() = field.toUpperCase()
        set

    /*Kotlin 中類不能有字段硕旗。提供了 Backing Fields(后端變量) 機(jī)制,備用字段使用field關(guān)鍵字聲明,field 關(guān)鍵詞只能用于屬性的訪問器*/
    var no: Int = 100
        get() = field
        set(value) {
            if (value < 10) {
                field = value
            } else {
                field = -1
            }
        }

    var height: Float = 145.4f
        private set
}

fun t_obj_person() {
    val person = Person()
    person.lastName = "ratel"
    println("lastName = ${person.lastName}")
    person.no = 9
    println("no = ${person.no}")
    person.no = 21
    println("no = ${person.no}")
}


public class MyTest {
    // 非空屬性必須在定義的時(shí)候初始化,kotlin提供了一種可以延遲初始化的方案,使用 lateinit 關(guān)鍵字描述屬性
    lateinit var subject: TestSubject

    @SetUp
    fun setup() {
        subject = TestSubject()
    }

    @Test
    fun test() {
        subject.method()
    }
}

annotation class SetUp
annotation class Test

class TestSubject {
    fun method() {
    }

}

/**主構(gòu)造器
 *  主構(gòu)造器中不能包含任何代碼,初始化代碼可以放在初始化代碼段中褪储,初始化代碼使用init關(guān)鍵字
 */
class BookBean constructor(name: String) {
    init {
        println("book name $name")
    }
}

/**
 * 注意:主構(gòu)造器的參數(shù)可以在初始化代碼段中使用卵渴,也可以在類主體n定義的屬性初始化代碼中使用慧域。 一種簡(jiǎn)潔語法鲤竹,可以通過主構(gòu)造器來定義屬性并初始化屬性值(可以是var或val):
 *  val 定義的常量是不可以修改的
 *  如果構(gòu)造器有注解,或者有可見度修飾符,這時(shí)constructor關(guān)鍵字是必須的辛藻,注解和修飾符要放在它之前碘橘。
 */
class People(val firstName: String, val lastName: String) {
    init {
        println("firstName $firstName , lastName $lastName")
    }
}

fun t_consutrctor() {
    BookBean("三國(guó)")
    People("kagle", "ai")
}


class Runoob constructor(name: String) {
    var url = "http://www.runoob.com"
    var contry: String = "CN"
    var siteName = name

    init {
        println("初始化網(wǎng)站名: $name")
    }

    fun printTest() {
        println("我是類的函數(shù)")
    }
}

fun t_runoob() {
    val runoob = Runoob("菜鳥教程")
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.contry)
    runoob.printTest()
}

/**
 * 次構(gòu)造函數(shù)
類也可以有二級(jí)構(gòu)造函數(shù),需要加前綴 constructor:
 */
class NewPerson {
    private val children: Children = Children()

    constructor(parent: NewPerson) {
        parent.children.add(this)
    }
}

/**
 * 如果類有主構(gòu)造函數(shù)吱肌,每個(gè)次構(gòu)造函數(shù)都要痘拆,或直接或間接通過另一個(gè)次構(gòu)造函數(shù)代理主構(gòu)造函數(shù)。
 * 在同一個(gè)類中代理另一個(gè)構(gòu)造函數(shù)使用 this 關(guān)鍵字:
 */
class NewPerson2 constructor(val name: String) {
    var age: Int = 0

    init {
        println("NewPerson2 init name : $name")
    }


    constructor(name: String, _age: Int) : this(name) {
        age = _age
        // 初始化
        println("NewPerson2 次構(gòu)造 : name : $name , age : $age")
    }
}

fun t_new_person2() {
    val newPerson2 = NewPerson2("zzg", 32)
    println("user name ${newPerson2.name} , age ${newPerson2.age}")
}

class Children {
    var pList = ArrayList<NewPerson>()

    fun add(person: NewPerson) {
        if (!pList.contains(person)) {
            pList.add(person)
        }
    }
}

/**
 *如果一個(gè)非抽象類沒有聲明構(gòu)造函數(shù)(主構(gòu)造函數(shù)或次構(gòu)造函數(shù))氮墨,它會(huì)產(chǎn)生一個(gè)沒有參數(shù)的構(gòu)造函數(shù)纺蛆。構(gòu)造函數(shù)是 public 。如果你不想你的類有
 * 公共的構(gòu)造函數(shù)规揪,你就得聲明一個(gè)空的主構(gòu)造函數(shù)
 */
class DontCreateMe private constructor() {

}

/**
 * 注意:在 JVM 虛擬機(jī)中桥氏,如果主構(gòu)造函數(shù)的所有參數(shù)都有默認(rèn)值,編譯器會(huì)生成一個(gè)附加的無參的構(gòu)造函數(shù)猛铅,這個(gè)構(gòu)造函數(shù)會(huì)直接使用默認(rèn)值字支。這使得 Kotlin 可以更簡(jiǎn)單的使用像 Jackson 或者 JPA 這樣使用無參構(gòu)造函數(shù)來創(chuàng)建類實(shí)例的庫(kù)。
class Customer(val customerName: String = "")
 */
/* -------------- 類和對(duì)象 -------------- */


/* -------------- 抽象類 -------------- */
/**
 * 抽象是面向?qū)ο缶幊痰奶卣髦患楹觯惐旧矶槲保蝾愔械牟糠殖蓡T,都可以聲明為abstract的栗菜。抽象成員在類中不存在具體的實(shí)現(xiàn)欠雌。
注意:無需對(duì)抽象類或抽象成員標(biāo)注open注解。
 */
open class BaseHandler {
    open fun f() {}
}

// 抽象類
abstract class BaseDefaultHanlder : BaseHandler() {
    // 抽象方法
    override abstract fun f()

}
/* -------------- 抽象類 -------------- */

/* -------------- 嵌套類(靜態(tài)內(nèi)部類) -------------- */
class Outer {
    private val bar: Int = 1

    class Nested {

        var ot: Outer = Outer()

        fun test() {
            // 嵌套類可以引用外部類私有變量疙筹,但要先創(chuàng)建外部類的實(shí)例桨昙,不能直接引用
            println(ot.bar)
        }

        fun foo() = 2
    }
}

// 調(diào)用格式:外部類.嵌套類.嵌套類方法/屬性
fun t_nest_cls() {
    // 嵌套類,Outter后邊沒有括號(hào)
    val foo = Outer.Nested().foo()
    println("foo = $foo")
}
/* -------------- 嵌套類(靜態(tài)內(nèi)部類) -------------- */

/* -------------- 內(nèi)部類 -------------- */
/**
 * 內(nèi)部類使用 inner 關(guān)鍵字來表示腌歉。
內(nèi)部類會(huì)帶有一個(gè)對(duì)外部類的對(duì)象的引用蛙酪,所以內(nèi)部類可以訪問外部類成員屬性和成員函數(shù)。
 */
class Outer2 {
    private val bar: Int = 2
    var v = "成員屬性"

    /*嵌套內(nèi)部類*/
    inner class Inner2 {
        // 訪問外部類成員
        fun foo() = bar

        fun innterTest() {
            // 獲取外部類的成員變量
            // 相當(dāng)于Outer.this
            /*
            為了消除歧義翘盖,要訪問來自外部作用域的 this桂塞,我們使用this@label,
            其中 @label 是一個(gè) 代指 this 來源的標(biāo)簽馍驯。
            */
            var o = this@Outer2
            println("Outer2 內(nèi)部類可以引用外部類的成員: v " + o.v)
        }
    }
}

fun t_inner_cls() {
    // 內(nèi)部類阁危,Outter后邊有括號(hào)
    //
    val foo = Outer2().Inner2().foo()
    println("t_inner_cls foo = $foo")

    val d = Outer2().Inner2().innterTest()
    println("t_inner_cls d = $d")
}
/* -------------- 內(nèi)部類 -------------- */

/* -------------- 匿名內(nèi)部類 -------------- */
/*使用對(duì)象表達(dá)式來創(chuàng)建匿名內(nèi)部類*/

class Test2 {
    var v = "成員屬性"

    fun setInterFace(test: ITest) {
        println("Test2 setInterFace v = $v ")
        test.test()
    }
}

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

fun t_anonymous() {
    val test2 = Test2()
    /**
     * 采用對(duì)象表達(dá)式來創(chuàng)建接口對(duì)象,即匿名內(nèi)部類的實(shí)例
     */
    test2.setInterFace(object : ITest {
        override fun test() {
            println("接口回調(diào),對(duì)象表達(dá)式創(chuàng)建匿名內(nèi)部類的實(shí)例")
        }
    })
}
/* -------------- 匿名內(nèi)部類 -------------- */

/* -------------- 類的修飾符 -------------- */
/**
 * 類的修飾符包括 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è)模塊中可見
 */
private fun foo() {} // 在包類可見趴乡,包級(jí)函數(shù)

public var bar: Int = 5 // 該屬性隨處可見

internal val baz = 6 // 相同模塊內(nèi)可見

/* -------------- 類的修飾符 -------------- */

fun main(args: Array<String>) {
    t_obj_person()
    t_consutrctor()
    t_runoob()
    t_new_person2()
    t_nest_cls()
    t_inner_cls()
    t_anonymous()
}

繼承

/* -------------- 繼承 -------------- */
/**
kotlin中所有的類都繼承Any,它是所有類的超父,對(duì)于沒有超類型聲明的類默認(rèn)繼承超類
class Exemaple // 從Any隱式繼承
Any默認(rèn)提供三個(gè)函數(shù):equals,hashCode,toString

Any不是java.lang.Object
如果一個(gè)類要被繼承,可以使用open關(guān)鍵字進(jìn)行修飾
 */

open class Base(p: Int) // 定義基類

class Dervied(p: Int) : Base(p)
/* -------------- 繼承 -------------- */

/* -------------- 構(gòu)造函數(shù) -------------- */
/**
 *子類有主構(gòu)造函數(shù)
如果子類有主構(gòu)造函數(shù)晾捏, 則基類必須在主構(gòu)造函數(shù)中立即初始化
 */
open class New_EPerson(var name: String, var age: Int) { // 基類

}

class Student(name: String, age: Int, var no: String, var score: Int) : New_EPerson(name, age) {

}

fun t_ext_obj() {
    val student = Student("runnob", 18, "S0035", 89)
    println("姓名: ${student.name}")
    println("年齡: ${student.age}")
    println("學(xué)生號(hào): ${student.no}")
    println("學(xué)分: ${student.score}")
}


/**
 *子類沒有主構(gòu)造函數(shù)
如果子類沒有主構(gòu)造函數(shù)蒿涎,則必須在每一個(gè)二級(jí)構(gòu)造函數(shù)中用 super 關(guān)鍵字初始化基類,
或者在代理另一個(gè)構(gòu)造函數(shù)惦辛。初始化基類時(shí)劳秋,可以調(diào)用基類的不同構(gòu)造方法。
 */

open class Animal constructor(ctx: Context) {
    // 次構(gòu)造
    constructor(ctx: Context, attrs: AttributeSet) : this(ctx)
}

class Cat : Animal {
    constructor(ctx: Context) : super(ctx)

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

//實(shí)例

open class User(name: String) {
    // 次級(jí)構(gòu)造函數(shù)
    constructor(name: String, age: Int) : this(name) {
        println("---------- 基類次級(jí)構(gòu)造函數(shù) ----------")
    }
}

class Worker : User {
    constructor(name: String, age: Int, no: String, score: Int) : super(name, age) {
        println("---------- 繼承類次級(jí)構(gòu)造函數(shù) ----------")
        println("Worker 姓名: $name")
        println("Worker 年齡: $age")
        println("Worker 學(xué)生號(hào): $no")
        println("Worker 學(xué)分: $score")
    }
}

fun t_ext_user() {
    Worker("test01", 23, "S1174", 135)
}


/**
 *重寫
在基類中胖齐,使用fun聲明函數(shù)時(shí)玻淑,此函數(shù)默認(rèn)為final修飾,不能被子類重寫呀伙。如果允許子類重寫該函數(shù)岁忘,
那么就要手動(dòng)添加 open 修飾它, 子類重寫方法使用 override 關(guān)鍵詞
 */
// 用戶基類
open class NewUser {
    open fun study() { // 允許子類重寫
        println("我畢業(yè)了")
    }
}

/*子類繼承NewUser類*/
class NewStudent : NewUser() {
    override fun study() { // 重寫方法
        println("我在讀大學(xué)")
    }
}

fun t_ode() {
    val student = NewStudent()
    student.study()
}

// 如果有多個(gè)相同的方法(繼承或者實(shí)現(xiàn)自其他類,如A区匠、B類)干像,則必須要重寫該方法,使用super范型去選擇性地調(diào)用父類的實(shí)現(xiàn)驰弄。
open class A {
    open fun f() {
        println("A")
    }

    fun a() {
        println("a")
    }
}

interface B {
    //  //接口的成員變量默認(rèn)是 open 的
    fun f() {
        println("B")
    }

    fun b() {
        println("b")
    }
}

class C() : A(), B {
    override fun f() {
        println("C run f ... ")
        // 選擇性的去調(diào)用父類的實(shí)現(xiàn)
        super<A>.f()
        super<B>.f()
    }
}

fun t_oc() {
    val c = C()
    c.f()
}

/**
 * 屬性重寫
屬性重寫使用 override 關(guān)鍵字麻汰,屬性必須具有兼容類型,每一個(gè)聲明的屬性都可以通過初始化程序或者getter方法被重寫:
 */
open class Foo {
    open val x: Int
        get() = 10
}

class Bar1 : Foo() {
    override val x: Int
        get() = super.x
}

/**
 *
你可以用一個(gè)var屬性重寫一個(gè)val屬性戚篙,但是反過來不行五鲫。因?yàn)関al屬性本身定義了getter方法卤橄,重寫為var屬性會(huì)在衍生類中額外聲明一個(gè)setter方法
你可以在主構(gòu)造函數(shù)中使用 override 關(guān)鍵字作為屬性聲明的一部分:
 */
interface IFoo {
    val count: Int
}

class Bar_1(override val count: Int) : IFoo

class Bar_2 : IFoo {
    override var count: Int = 0
}

/* -------------- 構(gòu)造函數(shù) -------------- */
fun main(args: Array<String>) {
    t_ext_obj()

    t_ext_user()

    t_ode()

    t_oc()
}

接口

/* -------------- 接口 -------------- */
//接口與java8類似寝受,使用interface定義撩荣,允許方法有默認(rèn)實(shí)現(xiàn)
interface IMe {
    fun bar()

    fun foo() {
        // 默認(rèn)實(shí)現(xiàn)
        println("foo")
    }
}

/**
 * 實(shí)現(xiàn)接口
 *  一個(gè)類或者對(duì)象可以實(shí)現(xiàn)一個(gè)或多個(gè)接口
 */
class MyChild : IMe {
    override fun bar() {
        println("bar")
    }
}

fun t_mychild() {
    val myChild = MyChild()
    myChild.bar()
    myChild.foo()
}

/**
 * 接口中的屬性
 * 接口中的屬性只能是抽象的吠裆,不允許初始化值,接口不會(huì)保存屬性值孵延,實(shí)現(xiàn)接口時(shí)贷腕,必須重寫屬性
 */
interface INewMe {
    // 抽象屬性
    var name: String
}

class NewMeImpl : INewMe {
    // 重寫屬性
    override var name: String = "runoob"
}

fun t_new_me() {
    val meImpl = NewMeImpl()
    println("name = ${meImpl.name}")
}

/**
 * 函數(shù)的重寫
 * 實(shí)現(xiàn)多個(gè)接口時(shí)惹苗,可能會(huì)遇到同一方法繼承多個(gè)實(shí)現(xiàn)的問題
 */
interface A_1 {
    fun foo() {
        println("A_1")
    }

    fun bar()
}

interface B_1 {
    fun foo() {
        println("B_1")
    }

    fun bar() {
        println("B_1 bar")
    }
}

class C_1 : A_1 {
    override fun bar() {
        println("C_1 bar")
    }

}

class D_1 : A_1, B_1 {
    override fun bar() {
        println("D_1 bar")
        super<B_1>.bar()
    }

    override fun foo() {
        println("D_1 foo")
        super<A_1>.foo()
        super<B_1>.foo()
    }
}

fun t_o_method() {
    val d_1 = D_1()
    d_1.foo()
    d_1.bar()
}

/**
 * 實(shí)例中接口 A 和 B 都定義了方法 foo() 和 bar()痛倚, 兩者都實(shí)現(xiàn)了 foo(), B 實(shí)現(xiàn)了 bar()规婆。因?yàn)?C 是一個(gè)實(shí)現(xiàn)了 A 的具體類,
 * 所以必須要重寫 bar() 并實(shí)現(xiàn)這個(gè)抽象方法蝉稳。

  然而抒蚜,如果我們從 A 和 B 派生 D,我們需要實(shí)現(xiàn)多個(gè)接口繼承的所有方法耘戚,并指明 D 應(yīng)該如何實(shí)現(xiàn)它們嗡髓。
  這一規(guī)則 既適用于繼承單個(gè)實(shí)現(xiàn)(bar())的方法也適用于繼承多個(gè)實(shí)現(xiàn)(foo())的方法。
 */
/* -------------- 接口 -------------- */
fun main(args: Array<String>) {
    t_mychild()
    t_new_me()
    t_o_method()
}

擴(kuò)展

package com.example.ext

/* -------------- 擴(kuò)展 -------------- */
/**
 * kotlin可以對(duì)一個(gè)類的屬性和方法進(jìn)行擴(kuò)展收津,且不需要使繼承或使用Decorator模式
 * 擴(kuò)展是一種靜態(tài)行為饿这,對(duì)于被擴(kuò)展的類代碼本身不會(huì)造成任何影響
 */

/**
 * 擴(kuò)展函數(shù)
 * 擴(kuò)展函數(shù)可以在已有的類中添加新的方法浊伙,不會(huì)對(duì)原類做修改
 * fun receiverType.functionName(params){
 *   body
 * }
 *
 * receiverType 要擴(kuò)展的類
 * functionName 方法名稱
 */

class New_User(var name: String)

// 擴(kuò)展函數(shù)
fun New_User.Print() {
    println("User .. $name")
}

fun t_user_print() {
    val user = New_User("zz")
    user.Print()
}

/**
 * 為MutableList添加一個(gè)swap函數(shù),交換不同位置的值
 */
fun MutableList<Int>.swap(_i: Int, _j: Int) {
    var tmp = this[_i]
    this[_i] = this[_j]
    this[_j] = tmp

    // this關(guān)鍵字指代接收者對(duì)象(receiver object)(也就是調(diào)用擴(kuò)展函數(shù)時(shí), 在點(diǎn)號(hào)之前指定的對(duì)象實(shí)例)。
}

fun t_change_item() {
    val l = mutableListOf(1, 2, 3)
    l.swap(0, 2)
    println(l.toString())
}


/**
 * 擴(kuò)展函數(shù)是靜態(tài)解析的
擴(kuò)展函數(shù)是靜態(tài)解析的蛹稍,并不是接收者類型的虛擬成員,在調(diào)用擴(kuò)展函數(shù)時(shí)部服,具體被調(diào)用的的是哪一個(gè)函數(shù)唆姐,由調(diào)用函數(shù)的的對(duì)象表達(dá)式來決定的,
而不是動(dòng)態(tài)的類型決定的:
 */

open class EC

class ED : EC()

fun EC.foo() = "c" // 擴(kuò)展函數(shù)foo

fun ED.foo() = "d" // 擴(kuò)展函數(shù)foo

/**
 * 無論方法傳遞的是哪個(gè)實(shí)例廓八,最終只會(huì)調(diào)用EC的擴(kuò)展函數(shù)
 */
fun printFoo(c: EC) {
    // 類型是c類型
    // c
    println(c.foo())
}

fun t_ext_method_2() {
    // 這里會(huì)走EC的擴(kuò)展函數(shù)
    printFoo(ED())

    // 這里才會(huì)走ED的擴(kuò)展函數(shù)
    println(ED().foo())
}

/**
 * 若擴(kuò)展函數(shù)和成員函數(shù)一致奉芦,則使用該函數(shù)時(shí),會(huì)優(yōu)先使用成員函數(shù)剧蹂。
 */
class NC {
    fun foo() {
        println("成員函數(shù)")
    }
}

fun NC.foo() {
    println("擴(kuò)展函數(shù)")
}

fun t_ext_method_3() {
    val nc = NC()
    nc.foo()
}

/**
 * 擴(kuò)展一個(gè)空對(duì)象
在擴(kuò)展函數(shù)內(nèi)声功, 可以通過 this 來判斷接收者是否為 NULL,這樣,即使接收者為 NULL,也可以調(diào)用擴(kuò)展函數(shù)
 */
fun Any?.toString(): String {
    if (this == null)
        return "null"
    // 空檢測(cè)之后宠叼,this自動(dòng)轉(zhuǎn)換為非空類型先巴,所以下面的toString
    // 解析為Any類的成員函數(shù)
    return toString()
}

fun t_ext_nul_obj() {
    var t = null
    println(t.toString())
}

/**
 * 擴(kuò)展屬性
除了函數(shù),Kotlin 也支持屬性對(duì)屬性進(jìn)行擴(kuò)展:

擴(kuò)展屬性允許定義在類或者kotlin文件中冒冬,不允許定義在函數(shù)中伸蚯。初始化屬性因?yàn)閷傩詻]有后端字段(backing field),所以不允許被初始化简烤,只能由顯式提供的 getter/setter 定義剂邮。

val Foo.bar = 1 // 錯(cuò)誤:擴(kuò)展屬性不能有初始化器
擴(kuò)展屬性只能被聲明為 val。
 */
val <T> List<T>.lastIndex: Int
    get() = size - 1


/**
 *
伴生對(duì)象的擴(kuò)展
如果一個(gè)類定義有一個(gè)伴生對(duì)象 横侦,你也可以為伴生對(duì)象定義擴(kuò)展函數(shù)和屬性挥萌。

伴生對(duì)象通過"類名."形式調(diào)用伴生對(duì)象,伴生對(duì)象聲明的擴(kuò)展函數(shù)枉侧,通過用類名限定符來調(diào)用
 */
class MyCls {
    companion object {
        // 將稱為Companion
    }
}

// 擴(kuò)展函數(shù)
fun MyCls.Companion.foo() {
    println("伴隨對(duì)象的擴(kuò)展函數(shù)")
}

// 擴(kuò)展字段
val MyCls.Companion.no: Int
    get() = 10

fun t_ext_companion() {
    println("no: ${MyCls.no}")
    MyCls.foo()
}


/**
 * 擴(kuò)展的作用域
 * 通常擴(kuò)展函數(shù)或?qū)傩远x在頂級(jí)包下:

package foo.bar

fun Baz.goo() { …… }

要使用所定義包之外的一個(gè)擴(kuò)展, 通過import導(dǎo)入擴(kuò)展的函數(shù)名進(jìn)行使用:

package com.example.usage

import foo.bar.goo // 導(dǎo)入所有名為 goo 的擴(kuò)展
// 或者
import foo.bar.*   // 從 foo.bar 導(dǎo)入一切

fun usage(baz: Baz) {
baz.goo()
}
 */

/**
 * 擴(kuò)展聲明為成員
在一個(gè)類內(nèi)部你可以為另一個(gè)類聲明擴(kuò)展引瀑。

在這個(gè)擴(kuò)展中,有個(gè)多個(gè)隱含的接受者榨馁,其中擴(kuò)展方法定義所在類的實(shí)例稱為分發(fā)接受者伤疙,而擴(kuò)展方法的目標(biāo)類型的實(shí)例稱為擴(kuò)展接受者。
 */
// 擴(kuò)展接受者
class EN_D {
    fun bar() {
        println("EN_D bar")
    }
}

// 分發(fā)接受者
class EN_C {
    fun baz() {
        println("EN_C baz")
    }

    fun EN_D.foo() {
        println("EN_C ext foo")
        bar()
        baz()
    }

    fun caller(d: EN_D) {
        println("EN_C caller")
        // 調(diào)用擴(kuò)展函數(shù)
        d.foo()
    }
}

fun t_ext_mem() {
    println("t_ext_mem")
    val c: EN_C = EN_C()
    val d: EN_D = EN_D()
    c.caller(d)
}

/**
 * 假如在調(diào)用某一個(gè)函數(shù)辆影,而該函數(shù)在分發(fā)接受者和擴(kuò)展接受者均存在徒像,則以擴(kuò)展接收者優(yōu)先,
 * 要引用分發(fā)接收者的成員你可以使用限定的 this 語法蛙讥。
 */
class END {
    fun bar() {
        println("END bar")
    }
}

class ENC() {
    fun bar() {
        println("ENC bar")
    }

    fun END.foo() {
        println("ENC foo")
        // 調(diào)用END.bar(),擴(kuò)展接收者優(yōu)先
        bar()
        this@ENC.bar() // 調(diào)用ENC.bar
    }

    fun caller(d: END) {
        println("ENC caller")
        // 調(diào)用擴(kuò)展函數(shù)
        d.foo()
    }
}

fun t_ext_mem_2() {
    println("t_ext_mem_2")
    val enc = ENC()
    val end = END()
    enc.caller(end)
}

// 調(diào)用 ->> 分發(fā)接收者 ->> 擴(kuò)展接收者

/**
 * 以成員的形式定義的擴(kuò)展函數(shù), 可以聲明為 open , 而且可以在子類中覆蓋. 也就是說, 在這類擴(kuò)展函數(shù)的派 發(fā)過程中,
 * 針對(duì)分發(fā)接受者是虛擬的(virtual), 但針對(duì)擴(kuò)展接受者仍然是靜態(tài)的锯蛀。
 */
open class EN2D {

}

class N2D : EN2D() {

}

open class EN2C {
    open fun EN2D.foo() {
        println("EN2D.foo in EN2C")
    }

    open fun N2D.foo() {
        println("N2D.foo in EN2C")
    }

    fun caller(d: EN2D) {
        println("EN2C caller")
        // 調(diào)用擴(kuò)展函數(shù)
        d.foo()
    }
}

class N2C : EN2C() {
    override fun EN2D.foo() {
        println("EN2D.foo in N2C")
    }

    override fun N2D.foo() {
        println("N2D.foo in N2C")
    }
}

fun t_ext_mem_3() {
    println(" t_ext_mem_3 ")
    println(" -------------- ")
    EN2C().caller(EN2D()) // EN2D.foo in EN2C
    println(" -------------- ")
    N2C().caller(EN2D()) // EN2D.foo in N2C
    println(" -------------- ")
    EN2C().caller(N2D()) // EN2D.foo in EN2C
}

class MyNewCls {
    companion object {
        val mFid1: Int = 1
        var mFid2 = "this is myCFid2"

        fun companionFun1() {
            println("MyNewCls this is 1st companion func")
            foo()
        }

        fun companionFun2() {
            println("MyNewCls this is 2st companion func")
            companionFun1()
        }
    }

    fun MyNewCls.Companion.foo() {
        println("MyNewCls 伴隨對(duì)象的擴(kuò)展函數(shù) (內(nèi)部) ")
    }

    fun test2() {
        println("MyNewCls test2 ")
        MyNewCls.foo()
    }

    init {
        println("MyNewCls init ")
        test2()
    }
}

val MyNewCls.Companion.no: Int
    get() = 10

fun MyNewCls.Companion.foo() {
    println("MyNewCls.Companion foo 伴隨對(duì)象外部擴(kuò)展函數(shù)")
}

fun t_ext_mem_4() {
    println("t_ext_mem_4")
    println("no: ${MyNewCls.no}")
    println("filed1:${MyNewCls.mFid1}")
    println("filed2:${MyNewCls.mFid2}")
    MyNewCls.foo()
    MyNewCls.companionFun2()
}

/* -------------- 擴(kuò)展 -------------- */

fun main(args: Array<String>) {
    t_user_print()
    t_change_item()
    t_ext_method_2()
    t_ext_method_3()
    t_ext_nul_obj()
    t_ext_companion()
    t_ext_mem()
    t_ext_mem_2()
    t_ext_mem_3()
    t_ext_mem_4()
}

數(shù)據(jù)類和密封類

/* -------------- 數(shù)據(jù)類 -------------- */
/**
kotlin可以創(chuàng)建一個(gè)只包含數(shù)據(jù)的類:data
data class User(val name:String,val age:Int)

編譯器會(huì)自動(dòng)的從主構(gòu)造函數(shù)中根據(jù)所有聲明的屬性提取以下函數(shù):
equals() / hashCode()
toString() 格式如 "User(name=John, age=42)"
componentN() functions 對(duì)應(yīng)于屬性,按聲明順序排列
copy() 函數(shù)

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

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

/**
 * 復(fù)制
復(fù)制使用 copy() 函數(shù),我們可以使用該函數(shù)復(fù)制對(duì)象并修改部分屬性
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
 */
data class Account(val name: String, val age: Int)

fun t_data() {
    var jack = Account(name = "Jack", age = 1)
    // 復(fù)制并修改部分屬性
    val olderJack = jack.copy(age = 2)
    println(jack)
    println(olderJack)
}

/**
 * 數(shù)據(jù)類以及解構(gòu)聲明
 * 組件函數(shù)允許數(shù)據(jù)在解構(gòu)聲明中使用
 */
fun t_data_dec_con() {
    val jane = Account("jane", 35)
    val (name, age) = jane
    println("$name , $age years of age") // jane , 35 years of age
}

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

/* -------------- 密封類 -------------- */
/**
 * 密封類用來表示受限的類繼承結(jié)構(gòu):當(dāng)一個(gè)值為有限幾種的類型, 而不能有任何其他類型時(shí)猾蒂。在某種意義上,他們是枚舉類的擴(kuò)展:
 *  枚舉類型的值集合 也是受限的是晨,但每個(gè)枚舉常量只存在一個(gè)實(shí)例肚菠,而密封類 的一個(gè)子類可以有可包含狀態(tài)的多個(gè)實(shí)例。
聲明一個(gè)密封類罩缴,使用 sealed 修飾類蚊逢,密封類可以有子類,但是所有的子類都必須要內(nèi)嵌在密封類中箫章。
sealed 不能修飾 interface ,abstract class(會(huì)報(bào) warning,但是不會(huì)出現(xiàn)編譯錯(cuò)誤)
 */
sealed class Expr

data class Const(val number: Double) : Expr()

data class Sum(val e1: Expr, val e2: Expr) : Expr()

/*
將類的聲明和定義該類的單例對(duì)象結(jié)合在一起(即通過object就實(shí)現(xiàn)了單例模式)

即將class關(guān)鍵字替換為object關(guān)鍵字时捌,來聲明一個(gè)類,與此同時(shí)也聲明它的一個(gè)對(duì)象炉抒。只要編寫這么多代碼奢讨,這個(gè)類就已經(jīng)是單例的了

 換句話說,object declaration的類最終被編譯成:一個(gè)類擁有一個(gè)靜態(tài)成員來持有對(duì)自己的引用焰薄,并且這個(gè)靜態(tài)成員的名稱為INSTANCE拿诸,當(dāng)然這個(gè)INSTANCE是單例的,故這里可以這么去使用塞茅。如果用Java代碼來聲明這個(gè)RepositoryManager的話亩码,可以有如下代碼:

class RepositoryManager{
    private RepositoryManager(){}
    public static final RepositoryManager INSTANCE = new RepositoryManager();

}

*/
object NotANumber : Expr()

// 使用密封類的關(guān)鍵好處在于使用 when 表達(dá)式 的時(shí)候,如果能夠 驗(yàn)證語句覆蓋了所有情況野瘦,就不需要為該語句再添加一個(gè) else 子句了描沟。
fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}

class ObjectOuter {
    object Inner {
        fun method() {
            println("I'm in inner class")
        }
    }
}

fun t_object_cls() {
    ObjectOuter.Inner.method()
}

/* -------------- 密封類 -------------- */
fun main(args: Array<String>) {
    t_data()

    t_data_dec_con()

    println("eval_1 ${eval(Const(35.0))}")
    println("eval_2 ${eval(Sum(Const(35.0), Const(35.0)))}")
    println("eval_2 ${eval(NotANumber)}")
    t_object_cls()
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鞭光,隨后出現(xiàn)的幾起案子吏廉,更是在濱河造成了極大的恐慌,老刑警劉巖惰许,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件席覆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡汹买,警方通過查閱死者的電腦和手機(jī)佩伤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門聊倔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人生巡,你說我怎么就攤上這事耙蔑。” “怎么了孤荣?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵甸陌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我垃环,道長(zhǎng)邀层,這世上最難降的妖魔是什么返敬? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任遂庄,我火速辦了婚禮,結(jié)果婚禮上劲赠,老公的妹妹穿的比我還像新娘涛目。我一直安慰自己,他們只是感情好凛澎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布霹肝。 她就那樣靜靜地躺著,像睡著了一般塑煎。 火紅的嫁衣襯著肌膚如雪沫换。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天最铁,我揣著相機(jī)與錄音讯赏,去河邊找鬼。 笑死冷尉,一個(gè)胖子當(dāng)著我的面吹牛漱挎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雀哨,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼磕谅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了雾棺?” 一聲冷哼從身側(cè)響起膊夹,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捌浩,沒想到半個(gè)月后割疾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘉栓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年宏榕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拓诸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡麻昼,死狀恐怖奠支,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抚芦,我是刑警寧澤倍谜,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站叉抡,受9級(jí)特大地震影響尔崔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褥民,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一季春、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧消返,春花似錦载弄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至倡勇,卻和暖如春逞刷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背妻熊。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工夸浅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人固耘。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓题篷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親厅目。 傳聞我的和親對(duì)象是個(gè)殘疾皇子番枚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,930評(píng)論 6 13
  • 面向?qū)ο缶幊蹋∣OP) 在前面的章節(jié)中葫笼,我們學(xué)習(xí)了Kotlin的語言基礎(chǔ)知識(shí)、類型系統(tǒng)拗馒、集合類以及泛型相關(guān)的知識(shí)路星。...
    Tenderness4閱讀 4,425評(píng)論 1 6
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 1,193評(píng)論 0 5
  • 1000個(gè)小確幸201~210:信仰 01今天突然變天诱桂,寒風(fēng)凜冽洋丐,差點(diǎn)凍成...... 02討論呈昔,一定要達(dá)成共識(shí)!...
    黑人灰灰閱讀 236評(píng)論 0 0
  • 如今的花園口遺址友绝,已經(jīng)被新建立的公園所取代堤尾。市民們?cè)诔鞘行鷩躺罡杏X煩悶的時(shí)候,來到此處休閑迁客,也是一個(gè)很好的選擇郭宝。廣
    emmmmmm哦閱讀 130評(píng)論 0 0