# 屬性與字段
參考[Java中的屬性和字段](http://www.hmoore.net/alex_wsc/java/1328553)
[TOC]
## 聲明屬性
Kotlin 類中的屬性既可以用關鍵字 *var* 聲明為可變的,也可以用關鍵字 *val*聲明為只讀的。
```kotlin
class Address {
var name: String = "Holmes, Sherlock"
var street: String = "Baker"
var city: String = "London"
var state: String? = null
var zip: String = "123456"
}
```
要使用一個屬性,只要用名稱引用它即可(和使用Java類字段(成員變量)差不多):
```kotlin
fun copyAddress(address: Address): Address {
val result = Address() // Kotlin 中沒有“new”關鍵字
result.name = address.name // 將調用訪問器
result.street = address.street
// ……
return result
}
```
* 用`val`修飾符修飾的屬性是只讀的,即不能被修改,只可使用
* 用`var`修飾符修飾的屬性是可讀寫的,即能用能改
示例:
```
class Mime{
val id : String = "123"
var name : String? = "kotlin"
var age : Int? = 22
var sex : String? = "男"
var weight : Float = 120.3f
private var test : String = ""
get() = "123"
set(value){field = value}
}
fun main(args: Array<String>) {
val mime = Mime()
println("id = ${mime.id} \t name = ${mime.name} \t age = ${mime.age}\t sex = ${mime.sex} \t weight = ${mime.weight}")
}
```
輸出結果
```
id = 123 name = kotlin age = 22 sex = 男 weight = 120.3
```
## Getters(讀訪問器) 與 Setters(寫訪問器)
在Kotlin中`getter`和`setter`?跟Java 中的getXX 和 setXX方法作用一樣,叫做**訪問器**。
> getter 叫讀訪問器,setter叫寫訪問器。`val`?聲明的變量只有讀訪問器getter,`var`聲明的變量讀寫訪問器都有。
聲明一個屬性的完整語法是
```
// 可變屬性
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
// 只讀屬性
val <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
```
其初始器(initializer)、getter 和 setter 都是可選的。
屬性類型PropertyType如果可以從初始器(或者從其 getter 返回值,如下文所示)中推斷出來,也可以省略。
例如:
```kotlin
var allByDefault: Int? // 錯誤:需要顯式初始化器,隱含默認 getter 和 setter
var initialized = 1 // 能推斷出屬性類型Int,使用默認的getter?和setter
```
一個只讀屬性的語法和一個可變的屬性的語法有兩方面的不同:
1、只讀屬性的用 `val`開始代替`var`
2、只讀屬性不允許 setter
```kotlin
val simple: Int? // 類型 Int、默認 getter、必須在構造函數中初始化
val inferredType = 1 // 類型 Int 、默認 getter
```
在Kotlin中,`getter`、`setter`?是屬性聲明的一部分,聲明一個屬性默認提供`getter`和`setter`?,當然了,如果有需要,你也可以自定義`getter`和`setter`。
* [ ] 在Kotlin 中,訪問一個屬性的實質是什么呢?
讀一個屬性,通過`.`表示,它的實質就是執行了屬性的getter訪問器,正如上面示例中的`mime.id`,**類似的,在Kotlin中,寫一個屬性的實質就是執行了屬性的寫訪問器setter**。示例如下
```
class Person {
var name:String = "Paul"
set(value) {
println("執行了寫訪問器,參數為:$value")
}
}
//測試
fun main(args: Array<String>) {
var person = Person()
// 寫name屬性
person.name = "hi,this is new value"
println("打印結果:${person.name}")
}
```
運行結果
```
執行了寫訪問器,參數為:hi,this is new value
打印結果:Paul
```
可以看到給一個給一個屬性賦值時,確實是執行了寫訪問器setter,但是為什么結果還是默認值Paul呢?因為我們重寫了setter,卻沒有給屬性賦值,當然還是默認值。如果需要給屬性賦值,則應如下操作:更改set方法
```
set(value)?{
println("執行了寫訪問器,參數為:$value")
this.name?=?value
}
```
但是,如果這樣運行,會報錯oom:`Your program produces too much output!`,一運行就會報錯,直接StackOverFlow了,內存溢出,為什么呢?轉換為Java代碼看一下你就明白了,將Person類轉為Java類:
```
public final class Person {
@NotNull
private String name = "Paul";
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String value) {
this.setName(value);
}
}
```
我們可以從set方法中看到,方法循環調用了,`setName`?中又調用了`setName`?,死循環了,直到內存溢出,程序崩潰。Kotlin代碼也一樣,在setter中又給屬性賦值,導致一直執行setter, 陷入死循環,直到內存溢出崩潰。那么這個怎么解決了?這就引入了Kotlin一個重要的東西**幕后字段(下面會講解到,這里留個疑問)**。
### 自定義Getter()與Setter()
我們可以為屬性自定義訪問器。如果我們定義了一個自定義的 getter,那么每次訪問該屬性時都會調用它(這讓我們可以實現計算出的屬性)。以下是一個自定義 getter 的示例:
```kotlin
val isEmpty: Boolean
get() = this.size == 0
```
* [ ] **示例1**:用`val`修飾的屬性自定義情況
```
class Mime{
// size屬性
private val size = 0
// 即isEmpty這個屬性,是判斷該類的size屬性是否等于0
val isEmpty : Boolean
get() = this.size == 0
// 另一個例子
val num = 2
get() = if (field > 5) 10 else 0
}
// 測試
fun main(args: Array<String>) {
val mime = Mime()
println("isEmpty = ${mime.isEmpty}")
println("num = ${mime.num}")
}
```
運行結果
```
isEmpty = true
num = 0
```
如果我們自定義了一個setter,那么每次給屬性賦值時都會調用它。一個自定義的 setter 如下所示:
```kotlin
var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value) // 解析字符串并賦值給其他屬性
}
```
按照慣例,setter 參數的名稱是 `value`,但是如果你喜歡也可以選擇一個不同的名稱(`value`是`Koltin`寫`setter()`函數時其參數的約定俗成的習慣。你也可以換成其他的值)。自 Kotlin 1.1 起,如果可以從 getter 推斷出屬性類型,則可以省略它:
```kotlin
val isEmpty get() = this.size == 0 // 具有類型 Boolean
```
* [ ] **示例2**:用`var`修飾的屬性自定義情況
```
class Mime{
var str1 = "test"
get() = field // 這句可以省略,kotlin默認實現的方式
set(value){
field = if (value.isNotEmpty()) value else "null"
}
var str2 = ""
get() = "隨意怎么修改都不會改變"
set(value){
field = if (value.isNotEmpty()) value else "null"
}
}
// 測試
fun main(args: Array<String>) {
val mime = Mime()
println("str = ${mime.str1}")
mime.str1 = ""
println("str = ${mime.str1}")
mime.str1 = "kotlin"
println("str = ${mime.str1}")
println("str = ${mime.str2}")
mime.str2 = ""
println("str = ${mime.str2}")
mime.str2 = "kotlin"
println("str = ${mime.str2}")
}
```
運行結果
```
str = test
str = null
str = kotlin
str = 隨意怎么修改都不會改變
str = 隨意怎么修改都不會改變
str = 隨意怎么修改都不會改變
```
* [ ] **結論**:
1. 使用了`val`修飾的屬性,不能有`setter()`.
2. 不管是`val`還是`var`修飾的屬性,只要存在`getter()`,其值再也不會變化
3. 使用`var`修飾的屬性,可以省略掉`getter()`,不然`setter()`毫無意義。當然`get() = field`除外。而`get() = field`是`Koltin`默認的實現,是可以省略這句代碼的。
PS:在實際的項目開發中,這個自定義的`getter`與`setter`的意義不是太大。
### 修改訪問器的可見性
如果你需要改變一個訪問器的可見性或者需要對其注解,但是不需要改變默認的實現,你可以定義訪問器而不定義其實現:
```kotlin
var setterVisibility: String = "abc"
private set // 此 setter 是私有的并且有默認實現,私有,不改變默認實現
var setterWithAnnotation: Any? = null
@Inject set // 用 Inject 注解此 setter,注解,不改變默認實現
```
示例:
```
var str1 = "kotlin_1"
private set // setter()訪問器的私有化,并且它擁有kotlin的默認實現
var test : String?
@Inject set // 用`Inject`注解去實現`setter()`
val str2 = "kotlin_2"
private set // 編譯錯誤,因為val修飾的屬性,不能有setter
var str3 = "kotlin_3"
private get // 編譯出錯,因為不能有getter()的訪問器可見性
fun main(args: Array<String>) {
// 這里偽代碼
str1 = "能不能重新賦值呢?" // 編譯出錯,因為上面的setter是私有的
}
```
**注意**:如果,屬性訪問器的可見性修改為`private`或者該屬性直接使用`private`修飾時,我們只能手動提供一個公有的函數去修改其屬性了。就像`Java`中的`Bean`的`setXXXX()`,另外,修改屬性訪問器在實際的開發中其實也沒有太大的作用。
>[success] 注意,
> 1、不存在`Getter()與Setter()`的,這只是`Kotlin`中的叫法而已,真正的寫法,還是用`get()、set()`
> 2、在`Kotlin`中,普通的類中一般是不提供`getter()`與`setter()`函數的,因為在普通的類中幾乎用不到,這一點和`Java`是相同的,但是`Java`中在定義純粹的數據類時,會用到`get()`與`set()`函數,但是`Kotlin`專門這種情況定義了`數據類`,這個特征。而`數據類`是系統已經為我們實現了`get()`和`set()`函數。
## 幕后字段
**在 Kotlin 類中不能直接聲明字段(fields)。然而,當一個屬性需要一個幕后字段時,Kotlin 會自動提供**。這個幕后字段可以**使用`field`標識符在訪問器中引用**,或者換一個說法就是,**在Kotlin中,如果屬性至少一個訪問器使用默認實現,那么Kotlin會自動提供幕后字段,用關鍵字`field`表示,幕后字段主要用于自定義getter和setter中,并且只能在getter 和setter中訪問**:
```kotlin
var counter = 0 // 注意:這個初始器直接為幕后字段賦值
set(value) {
if (value >= 0) field = value
}
```
```
var count = 0 // 初始化值會直接寫入備用字段
set(value){
field = if(value > 10) value else 0 // 通過field來修改屬性的值。
}
```
`field` 標識符只能用在屬性的訪問器內。
如果屬性至少一個訪問器使用默認實現,或者自定義訪問器通過 `field` 引用幕后字段,將會為該屬性生成一個幕后字段。
例如,下面的情況下,不會生成幕后字段的屬性,就沒有幕后字段:
```kotlin
val size = 0
/*
沒有幕后字段的原因:
1. 并且`getter()`不是默認的實現。沒有使用到`field`標識符
2. 使用`val`修飾,故而不存在默認的`setter()`訪問器,也沒有`field`修飾符
*/
val isEmpty: Boolean
get() = this.size == 0
```
>[info] 注意:不管是幕后字段或者下面的幕后屬性,都是`Kotlin`對于空指針的一種解決方案,可以避免函數訪問私有屬性而破壞它的結構。
正如前面我們講到的在[Getters(讀訪問器) 與 Setters(寫訪問器)](http://www.hmoore.net/alex_wsc/android_kotlin/1318250#Getters__Setters_49)這一小節中,自定義寫訪問器中,
```
set(value)?{
println("執行了寫訪問器,參數為:$value")
this.name?=?value
}
```
這樣會陷入死循環(原因見前面),這時就需要幕后字段,給幕后字段field賦值
```
class Person {
//錯誤的演示
var name = ""
set(value) {
field = value
}
}
```
getter 也一樣,返回了幕后字段:
```
// 例子一
class Person {
var name:String = ""
get() = field
set(value) {
field = value
}
}
// 例子二
class Person {
var name:String = ""
}
```
上面兩個屬性的聲明是等價的,例子一中的`getter`和`setter`?就是默認的`getter`和`setter`。其中幕后字段`field`指的就是當前的這個屬性,它不是一個關鍵字,只是在setter和getter的這個兩個特殊作用域中有著特殊的含義,就像一個類中的`this`,代表當前這個類。
用幕后字段,我們可以在getter和setter中做很多事,一般用于讓一個屬性在不同的條件下有不同的值,比如下面這個場景
**場景:**?我們可以根據性別的不同,來返回不同的姓名
```
class Person(var gender:Gender){
var name:String = ""
set(value) {
field = when(gender){
Gender.MALE -> "Jake.$value"
Gender.FEMALE -> "Rose.$value"
}
}
}
enum class Gender{
MALE,
FEMALE
}
fun main(args: Array<String>) {
// 性別MALE
var person = Person(Gender.MALE)
person.name="Love"
println("打印結果:${person.name}")
//性別:FEMALE
var person2 = Person(Gender.FEMALE)
person2.name="Love"
println("打印結果:${person2.name}")
}
```
打印結果
```
打印結果:Jake.Love
打印結果:Rose.Love
```
如上,我們實現了name 屬性通過gender 的值不同而行為不同。幕后字段大多也用于類似場景。
是不是Kotlin 所有屬性都會有幕后字段呢?當然不是,需要滿足下面條件之一:
* 使用默認 getter / setter 的屬性,一定有幕后字段。對于 var 屬性來說,只要 getter / setter 中有一個使用默認實現,就會生成幕后字段;
* 在自定義 getter / setter 中使用了 field 的屬性
正如下面的示例就沒有幕后字段
```
class?NoField?{
var?size?=?0
//isEmpty沒有幕后字段
var?isEmpty
get()?=?size?==?0
set(value)?{
????????????size?\*=?2
????????}
}
```
如上,`isEmpty`是沒有幕后字段的,重寫了setter和getter,沒有在其中使用?`field`,這或許有點不好理解,我們把它轉換成Java代碼看一下你可能就明白了,Java 代碼如下
```
public final class NoField {
private int size;
public final int getSize() {
return this.size;
}
public final void setSize(int var1) {
this.size = var1;
}
public final boolean isEmpty() {
return this.size == 0;
}
public final void setEmpty(boolean value) {
this.size *= 2;
}
}
```
看到沒,翻譯成Java代碼,只有一個size變量,isEmpty 翻譯成了?`isEmpty()`和`setEmpty()`兩個方法。返回值取決于size的值。
**有幕后字段的屬性轉換成Java代碼一定有一個對應的Java變量**
## 幕后屬性
### 官方文檔介紹
如果你的需求不符合這套“隱式的幕后字段”方案,那么總可以使用 *幕后屬性(backing property)*:
```kotlin
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // 類型參數已推斷出
}
return _table ?: throw AssertionError("Set to null by another thread")
}
```
> **對于 JVM 平臺**:通過默認 getter 和 setter 訪問私有屬性會被優化,所以本例不會引入函數調用開銷。
### 個人見解
有時候有這種需求,我們希望一個屬性:**對外表現為只讀,對內表現為可讀可寫**,我們將這個屬性成為**幕后屬性**。 如:
```
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // 類型參數已推斷出
}
return _table ?: throw AssertionError("Set to null by another thread")
}
```
將`_table`屬性聲明為`private`,因此外部是不能訪問的,內部可以訪問,外部訪問通過`table`屬性,而`table`屬性的值取決于`_table`,這里`_table`就是幕后屬性。
幕后屬性這種設計在Kotlin 的的集合Collection中用得非常多,Collection 中有個`size`字段,`size`?對外是只讀的,`size`的值的改變根據集合的元素的變換而改變,這是在集合內部進行的,這用幕后屬性來實現非常方便。
如Kotlin?`AbstractList`中`SubList`源碼:
```
private class SubList<out E>(private val list: AbstractList<E>, private val fromIndex: Int, toIndex: Int) : AbstractList<E>(), RandomAccess {
// 幕后屬性
private var _size: Int = 0
init {
checkRangeIndexes(fromIndex, toIndex, list.size)
this._size = toIndex - fromIndex
}
override fun get(index: Int): E {
checkElementIndex(index, _size)
return list[fromIndex + index]
}
override val size: Int get() = _size
}
```
`AbstractMap`?源碼中的keys 和 values 也用到了幕后屬性
```
/**
* Returns a read-only [Set] of all keys in this map.
*
* Accessing this property first time creates a keys view from [entries].
* All subsequent accesses just return the created instance.
*/
override val keys: Set<K>
get() {
if (_keys == null) {
_keys = object : AbstractSet<K>() {
override operator fun contains(element: K): Boolean = containsKey(element)
override operator fun iterator(): Iterator<K> {
val entryIterator = entries.iterator()
return object : Iterator<K> {
override fun hasNext(): Boolean = entryIterator.hasNext()
override fun next(): K = entryIterator.next().key
}
}
override val size: Int get() = this@AbstractMap.size
}
}
return _keys!!
}
@kotlin.jvm.Volatile
```
## 編譯期常量
已知值的屬性可以使用 *const*修飾符標記為 _編譯期常量_。這些屬性需要滿足以下要求:
* 位于頂層或者是 [object聲明](http://www.kotlincn.net/docs/reference/object-declarations.html#%E5%AF%B9%E8%B1%A1%E5%A3%B0%E6%98%8E) 或 [companion object(伴生對象)](http://www.kotlincn.net/docs/reference/object-declarations.html#%E4%BC%B4%E7%94%9F%E5%AF%B9%E8%B1%A1) 的一個成員
* 以 `String` 或原生類型值初始化(初始化為`String`類型或基本類型的值)
* 沒有自定義 getter
如
```
const val CONST_NUM = 5
const val CONST_STR = "Kotlin"
```
這些屬性可以用在注解中:
```kotlin
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { …… }
```
可參考:[Kotlin之常量的用法](http://www.hmoore.net/alex_wsc/android_kotlin/1037791#Kotlin_170)
## 延遲初始化屬性與變量
**一般地,屬性聲明為非空類型必須在構造函數中初始化**。然而,這經常不方便。例如:**屬性可以通過依賴注入來初始化,或者在單元測試的 setup 方法中初始化。 這種情況下,你不能在構造函數內提供一個非空初始器。但你仍然想在類體中引用該屬性時避免空檢測。**
為處理這種情況,你**可以用 `lateinit` 修飾符標記該屬性**:
```kotlin
public class MyTest {
lateinit var subject: TestSubject
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 直接解引用
}
}
```
*****
該修飾符只能用于在類體中的屬性(不是在主構造函數中聲明的 `var` 屬性,并且僅當該屬性沒有自定義 getter 或 setter 時),而自 Kotlin 1.2 起,也用于頂層屬性與局部變量。該屬性或變量必須為非空類型,并且不能是原生類型(原生類型指 Int、Float、Double、Short等,String類型是可以的)。
*****
在初始化前訪問一個 `lateinit` 屬性會拋出一個特定異常,該異常明確標識該屬性被訪問及它沒有初始化的事實。
### 檢測一個 lateinit var 是否已初始化(自 1.2 起)
要檢測一個 `lateinit var` 是否已經初始化過,請在[該屬性的引用](http://www.kotlincn.net/docs/reference/reflection.html#%E5%B1%9E%E6%80%A7%E5%BC%95%E7%94%A8)上使用`.isInitialized`:
```kotlin
if (foo::bar.isInitialized) {
println(foo.bar)
}
```
此檢測僅對可詞法級訪問的屬性可用,即聲明位于同一個類型內、位于其中一個外圍類型中或者位于相同文件的頂層的屬性。
## 覆蓋屬性
參見[覆蓋屬性](http://www.kotlincn.net/docs/reference/classes.html#%E8%A6%86%E7%9B%96%E5%B1%9E%E6%80%A7)
## 委托屬性
最常見的一類屬性就是簡單地從幕后字段中讀取(以及可能的寫入)。另一方面,使用自定義 getter 和 setter 可以實現屬性的任何行為。介于兩者之間,屬性如何工作有一些常見的模式。一些例子:惰性值、通過鍵值從映射讀取、訪問數據庫、訪問時通知偵聽器等等。
這些常見行為可以通過使用[_委托屬性_](http://www.kotlincn.net/docs/reference/delegated-properties.html)實現為庫。
- 前言
- Kotlin簡介
- IntelliJ IDEA技巧總結
- idea設置類注釋和方法注釋模板
- 像Android Studion一樣創建工程
- Gradle
- Gradle入門
- Gradle進階
- 使用Gradle創建一個Kotlin工程
- 環境搭建
- Androidstudio平臺搭建
- Eclipse的Kotlin環境配置
- 使用IntelliJ IDEA
- Kotlin學習路線
- Kotlin官方中文版文檔教程
- 概述
- kotlin用于服務器端開發
- kotlin用于Android開發
- kotlin用于JavaScript開發
- kotlin用于原生開發
- Kotlin 用于數據科學
- 協程
- 多平臺
- 新特性
- 1.1的新特性
- 1.2的新特性
- 1.3的新特性
- 開始
- 基本語法
- 習慣用法
- 編碼規范
- 基礎
- 基本類型
- 包與導入
- 控制流
- 返回與跳轉
- 類與對象
- 類與繼承
- 屬性與字段
- 接口
- 可見性修飾符
- 擴展
- 數據類
- 密封類
- 泛型
- 嵌套類
- 枚舉類
- 對象
- 類型別名
- 內嵌類
- 委托
- 委托屬性
- 函數與Lambda表達式
- 函數
- Lambda表達式
- 內聯函數
- 集合
- 集合概述
- 構造集合
- 迭代器
- 區間與數列
- 序列
- 操作概述
- 轉換
- 過濾
- 加減操作符
- 分組
- 取集合的一部分
- 取單個元素
- 排序
- 聚合操作
- 集合寫操作
- List相關操作
- Set相關操作
- Map相關操作
- 多平臺程序設計
- 平臺相關聲明
- 以Gradle創建
- 更多語言結構
- 解構聲明
- 類型檢測與轉換
- This表達式
- 相等性
- 操作符重載
- 空安全
- 異常
- 注解
- 反射
- 作用域函數
- 類型安全的構造器
- Opt-in Requirements
- 核心庫
- 標準庫
- kotlin.test
- 參考
- 關鍵字與操作符
- 語法
- 編碼風格約定
- Java互操作
- Kotlin中調用Java
- Java中調用Kotlin
- JavaScript
- 動態類型
- kotlin中調用JavaScript
- JavaScript中調用kotlin
- JavaScript模塊
- JavaScript反射
- JavaScript DCE
- 原生
- 并發
- 不可變性
- kotlin庫
- 平臺庫
- 與C語言互操作
- 與Object-C及Swift互操作
- CocoaPods集成
- Gradle插件
- 調試
- FAQ
- 協程
- 協程指南
- 基礎
- 取消與超時
- 組合掛起函數
- 協程上下文與調度器
- 異步流
- 通道
- 異常處理與監督
- 共享的可變狀態與并發
- Select表達式(實驗性)
- 工具
- 編寫kotlin代碼文檔
- 使用Kapt
- 使用Gradle
- 使用Maven
- 使用Ant
- Kotlin與OSGI
- 編譯器插件
- 編碼規范
- 演進
- kotlin語言演進
- 不同組件的穩定性
- kotlin1.3的兼容性指南
- 常見問題
- FAQ
- 與Java比較
- 與Scala比較(官方已刪除)
- Google開發者官網簡介
- Kotlin and Android
- Get Started with Kotlin on Android
- Kotlin on Android FAQ
- Android KTX
- Resources to Learn Kotlin
- Kotlin樣品
- Kotlin零基礎到進階
- 第一階段興趣入門
- kotlin簡介和學習方法
- 數據類型和類型系統
- 入門
- 分類
- val和var
- 二進制基礎
- 基礎
- 基本語法
- 包
- 示例
- 編碼規范
- 代碼注釋
- 異常
- 根類型“Any”
- Any? 可空類型
- 可空性的實現原理
- kotlin.Unit類型
- kotlin.Nothing類型
- 基本數據類型
- 數值類型
- 布爾類型
- 字符型
- 位運算符
- 變量和常量
- 語法和運算符
- 關鍵字
- 硬關鍵字
- 軟關鍵字
- 修飾符關鍵字
- 特殊標識符
- 操作符和特殊符號
- 算術運算符
- 賦值運算符
- 比較運算符
- 邏輯運算符
- this關鍵字
- super關鍵字
- 操作符重載
- 一元操作符
- 二元操作符
- 字符串
- 字符串介紹和屬性
- 字符串常見方法操作
- 字符串模板
- 數組
- 數組介紹創建及遍歷
- 數組常見方法和屬性
- 數組變化以及下標越界問題
- 原生數組類型
- 區間
- 正向區間
- 逆向區間
- 步長
- 類型檢測與類型轉換
- is、!is、as、as-運算符
- 空安全
- 可空類型變量
- 安全調用符
- 非空斷言
- Elvis操作符
- 可空性深入
- 可空性和Java
- 函數
- 函數式編程概述
- OOP和FOP
- 函數式編程基本特性
- 組合與范疇
- 在Kotlin中使用函數式編程
- 函數入門
- 函數作用域
- 函數加強
- 命名參數
- 默認參數
- 可變參數
- 表達式函數體
- 頂層、嵌套、中綴函數
- 尾遞歸函數優化
- 函數重載
- 控制流
- if表達式
- when表達式
- for循環
- while循環
- 循環中的 Break 與 continue
- return返回
- 標簽處返回
- 集合
- list集合
- list集合介紹和操作
- list常見方法和屬性
- list集合變化和下標越界
- set集合
- set集合介紹和常見操作
- set集合常見方法和屬性
- set集合變換和下標越界
- map集合
- map集合介紹和常見操作
- map集合常見方法和屬性
- map集合變換
- 集合的函數式API
- map函數
- filter函數
- “ all ”“ any ”“ count ”和“ find ”:對集合應用判斷式
- 別樣的求和方式:sumBy、sum、fold、reduce
- 根據人的性別進行分組:groupBy
- 扁平化——處理嵌套集合:flatMap、flatten
- 惰性集合操作:序列
- 區間、數組、集合之間轉換
- 面向對象
- 面向對象-封裝
- 類的創建及屬性方法訪問
- 類屬性和字段
- 構造器
- 嵌套類(內部類)
- 枚舉類
- 枚舉類遍歷&枚舉常量常用屬性
- 數據類
- 密封類
- 印章類(密封類)
- 面向對象-繼承
- 類的繼承
- 面向對象-多態
- 抽象類
- 接口
- 接口和抽象類的區別
- 面向對象-深入
- 擴展
- 擴展:為別的類添加方法、屬性
- Android中的擴展應用
- 優化Snackbar
- 用擴展函數封裝Utils
- 解決煩人的findViewById
- 擴展不是萬能的
- 調度方式對擴展函數的影響
- 被濫用的擴展函數
- 委托
- 委托類
- 委托屬性
- Kotlin5大內置委托
- Kotlin-Object關鍵字
- 單例模式
- 匿名類對象
- 伴生對象
- 作用域函數
- let函數
- run函數
- with函數
- apply函數
- also函數
- 標準庫函數
- takeIf 與 takeUnless
- 第二階段重點深入
- Lambda編程
- Lambda成員引用高階函數
- 高階函數
- 內聯函數
- 泛型
- 泛型的分類
- 泛型約束
- 子類和子類型
- 協變與逆變
- 泛型擦除與實化類型
- 泛型類型參數
- 泛型的背后:類型擦除
- Java為什么無法聲明一個泛型數組
- 向后兼容的罪
- 類型擦除的矛盾
- 使用內聯函數獲取泛型
- 打破泛型不變
- 一個支持協變的List
- 一個支持逆變的Comparator
- 協變和逆變
- 第三階段難點突破
- 注解和反射
- 聲明并應用注解
- DSL
- 協程
- 協程簡介
- 協程的基本操作
- 協程取消
- 管道
- 慕課霍丙乾協程筆記
- Kotlin與Java互操作
- 在Kotlin中調用Java
- 在Java中調用Kotlin
- Kotlin與Java中的操作對比
- 第四階段專題練習
- 朱凱Kotlin知識點總結
- Kotlin 基礎
- Kotlin 的變量、函數和類型
- Kotlin 里那些「不是那么寫的」
- Kotlin 里那些「更方便的」
- Kotlin 進階
- Kotlin 的泛型
- Kotlin 的高階函數、匿名函數和 Lambda 表達式
- Kotlin協程
- 初識
- 進階
- 深入
- Kotlin 擴展
- 會寫「18.dp」只是個入門——Kotlin 的擴展函數和擴展屬性(Extension Functions / Properties)
- Kotlin實戰-開發Android