Kotlin入門-被拆分了實例化,類與構造函數篇

在這裏插入圖片描述

前言

Kotlin簡化了結構體的編碼工作量。因此,引入了主\次構造函數。

主構造函數:減少了編碼的工作量。
次構造函數:提供了多態的特性,同樣的,也提供了java中可以定義多個結構體

除了文字版本,也有Xmind版本 github地址

帶着問題前進
① 爲什麼需要 包別名?
② 主、次構造函數分開存在有什麼價值?
③ private、protected、internal、public四個權限什麼區別
④ 實例的創建,匿名內部類、嵌套類的訪問權限如何?

本文從以下幾個方面來看

  • 包與導入
  • 構造函數 //敲黑板,這塊莫名的感覺有趣
    • 主構造函數
    • 次構造函數
  • 創建類的實例
  • 抽象類
  • 嵌套類
  • 內部類
  • 匿名內部類
  • 類的修飾符

包與導入

這部分基本與java一樣
要注意 導入部分。支持導入包的別名

import org.example.Message // 現在 Message 可以不用限定符訪問
如果出現名字衝突,可以使用 as 關鍵字
import org.example.Message // Message 可訪問
import org.test.Message as testMessage // testMessage 代表“org.test.Message”

構造函數

構造函數,就是在object實例化時會被調用的function。

在Kotlin中,稍微有點不一樣。

Kotlin有兩種構造函數

  • 主構造函數 - 提供簡潔的方式去初始化class
  • 次構造函數 - 允許你增加一些初始化邏輯

主構造函數

先來個範例

class Person constructor (val firstName: String, var age: Int) {
    // class body
}

結構體聲明瞭兩個參數,val不可變的firstName,var可變的age。

constructor關鍵字

constructor,在主構造函數沒有任何註解或者可見性修飾符,是可以省略的

那什麼時候是必須的呢?

class Customer public @Inject constructor(name: String) { /*……*/ }

如果構造函數有註解或可見性修飾符 -> 這個 constructor 關鍵字是必需的

可見性修飾符在Kotlin中有四個:
  • private - 意味着只在這個類內部(包含其所有成員)可見
  • protected - 和 private一樣 + 在子類中可見
  • internal - 能見到類聲明的 本模塊內 的任何客戶端都可見其 internal 成員
  • public - 如果沒有顯式指定修飾符的話,默認可見性是 public。

相比java,將java的protected拆爲protected+internal。

主構造函數不能包含任何的代碼;

初始化的代碼可以放在init關鍵字作爲前綴的初始化塊中。

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints ${name}")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

輸出

First property: hello
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5

在這裏,變量的定義和init都可以有多個,按順序執行。

注意

在 JVM 上,如果主構造函數的所有的參數都有默認值
編譯器會生成 一個額外的無參構造函數,它將使用默認值

常見的用法一

fun main(args: Array<String>) {
    val person1 = Person("Joe", 25)
    println("First Name = ${person1.firstName}")
    println("Age = ${person1.age}")
}
class Person(val firstName: String, var age: Int) {
}

這裏直接將firstName、age兩個參數。引入。
輸出

First Name = Joe
Age = 25

常用的用法二

fun main(args: Array<String>) {
    val person1 = Person("joe", 25)
}
class Person(fName: String, personAge: Int) {
    val firstName: String
    var age: Int
    // initializer block
    init {
        firstName = fName.capitalize()
        age = personAge
        println("First Name = $firstName")
        println("Age = $age")
    }
}
講解

結構體的參數fName,personAge,沒有定義val或var,默認就是val
init中,對fName、personAge做了二次處理。


次構造函數

次構造函數是個option選項。可以沒有。也可以有多個。
可以聲明前綴有 constructor的次構造函數
比如這樣

class Person {
    var children: MutableList<Person> = mutableListOf<Person>();
    constructor(parent: Person) {
        parent.children.add(this)
    }
}

次構造函數可以委託給主構造函數

委託到同一個類的另一個構造函數用 this 關鍵字

class Person(val name: String) {
    var children: MutableList<Person> = mutableListOf<Person>();
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

所有初始化塊中的代碼都會在次構造函數體之前執行

即使該類沒有主構造函數,這種委託仍會隱式發生,並且仍會執行初始化塊:

class Constructors {
    init {
        println("Init block")
    }

    constructor(i: Int) {
        println("Constructor")
    }
}

fun main() {
    Constructors(1)
}

輸出

Init block
Constructor

如果你不希望你的類有一個公有構造函數,
你需要聲明一個帶有非默認可見性的空的主構造函數:

class DontCreateMe private constructor () { /*……*/ }

我想起了,java中的必須單例模式,結構體聲明爲private的。
在kotlin中又可以少些幾行代碼。


創建類的實例

Kotlin 並沒有 new 關鍵字。

val invoice = Invoice()
val customer = Customer("Joe Smith")

抽象類

用abstract來聲明
類本身,或類中的部分成員,都可以聲明
注意:無需對抽象類或抽象成員標註open註解。因爲這不言而喻

open class Polygon {
    open fun draw() {}
}

abstract class Rectangle : Polygon() {
    override abstract fun draw()
}

嵌套類

跟java一樣,用範例來講解

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

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

看出來了嗎?
這裏的Outer.Nested()其實是類似於public static class


內部類

內部類使用 inner 關鍵字來表示
注意

  • 內部類會帶有一個對外部類的對象的引用
  • 內部類可以訪問外部類成員屬性和成員函數
    範例
class Outer {
    private val bar: Int = 1
    var v = "成員屬性"
    /**嵌套內部類**/
    inner class Inner {
        fun foo() = bar  // 訪問外部類成員
        fun innerTest() {
            var o = this@Outer //獲取外部類的成員變量
            println("內部類可以引用外部類的成員,例如:" + o.v)
        }
    }
}

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

注意這裏的Outer().inner().InnerTest()
這裏的內部類,必須通過 包裹它的 外部類才能訪問
就相當於 public class,沒有static


匿名內部類

與java一樣,參考自定的一個onXXXXClickListener


類的修飾符

classModifier

類屬性修飾符,標示類本身特性。
與 java一樣,有以下幾類

  • abstract // 抽象類
  • final // 類不可繼承,默認屬性
  • enum // 枚舉類
  • annotation // 註解類

Kotlin額外增加了關鍵字open
// 類可繼承,類默認是final的
抽象類中用到

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

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

accessModifier

訪問權限修飾符

  • private // 僅在同一個文件中可見
  • protected // 同一個文件中或子類可見
  • public // 所有調用的地方都可見
  • internal // 同一個模塊中可見

小結

Kotlin簡化了結構體的編碼工作量。因此,引入了主\次構造函數。

主構造函數:減少了編碼的工作量。
次構造函數:提供了多態的特性,同樣的,也提供了java中可以定義多個結構體

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章