前言
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中可以定義多個結構體