Java中有可見性修飾符(private
…),而Kotlin中也是有這樣的修飾符,但也有一些不一樣,下面來學習Kotlin中的可見性修飾符(Visibility Modifiers)和數據類(Data Classes)的相關知識。
可見性修飾符(Visibility Modifiers)
Kotlin有四種可見性修飾符,分別是public
、internal
、protected
和private
,默認的修飾符是public
,除了internal
之外,其他三種修飾符與Java的訪問權限一樣。
Kotlin的可見性除了用於類,對象,接口,構造函數,屬性之外,還用於屬性的setter
方法(getter
的可見性是由屬性的可見性決定的)。
屬性可見性修飾
// 文件名: example.kt
package foo
private fun foo() {} // 在example.kt中可見
public var bar: Int = 5 // 任何地方都可見
// 因爲get的可見性是由屬性決定的,所有這裏的get的可見性爲public
private set // setter在example.kt中可見
internal val baz = 6 // 在模塊中可見
注意:protected
在Top-level中不可以使用
private
修飾的屬性是不會自動生成get和set方法的
在Kotlin中可以使用使用屬性名來直接獲取值和設置值的,原因就是Kotlin會自動生成屬性的get
和set
方法
但是,如果如果設置屬性的可見性是private
的話,我們知道private
修飾的是私有的,也就是當前類可用,那麼就不會自動生成get
和set
方法了,不能給外部訪問。
類和接口的可見性修飾
open class Outer {
private val a = 1 // 在Outer類中可見
protected open val b = 2 // 在Outer類和子類中可見
internal val c = 3 // 在模塊中可見
val d = 4 // 默認爲public
protected class Nested {
public val e: Int = 5
}
}
class Subclass : Outer() {
// a不可見
// b,c和d可見
// Nested類和e可見
override val b = 5 // 重寫後的b依然是protected
}
class Unrelated(o: Outer) {
// o.a和o.b不可見
// o.d可見,在相同模塊下o.c可見
// Outer.Nested不可見, Nested::e也是不可見
}
注意:外部類不可以訪問內部類的private
成員。
構造函數同樣可以設置可見性,前面說過,在設置主構造函數的可見性或者註解的時候,要加上constructor
關鍵字。
class C @Inject private constructor(a: Int) { ... }
Kotlin中局部變量,函數和類是不允許使用修飾符的。
模塊(Modules)
internal
權限是是模塊級別的訪問權限,可以訪問本模塊的internal
變量和方法,當跨模塊的時候就無法訪問另一個模塊的internal
變量或方法。
數據類(Data Classes)
前面說過(Kotlin學習(五): 慣用語法和代碼風格),Kotlin的慣用語法是有寫POJO類,一般寫那種類都是用data
修飾的類,也就是數據類表示,只保存數據的類。
data class User(val name: String, val age: Int)
編譯器自動從主構造函數中聲明的所有屬性生成以下方法
可以看出有 getter
和setter
方法,還有componentN()
函數,對應按聲明順序出現的所有屬性,如name
就是component1()
,age
就是component2()
。
當然還有 equals()
、hashCode()
、和 toString()
(輸出的格式爲User(name=..., age=...)
),爲什麼生成的class文件中沒有這三個類,但是又可以直接調用呢?
Any
類是Kotlin每個類的超類,所以自然可以調用這幾個方法。
爲了確保數據類生成的代碼的一致性和有意義,必須滿足
- 如果構造函數參數中沒有聲明是val
或者var
,這些函數就不會生成
- 主構造函數需要有至少一個參數
- 數據類不能有abstract
、open
、sealed
和inner
修飾
- 在1.1版本之前,數據類只能實現接口
在構造函數那裏也說過,如果生成的類需要一個無參數的構造函數,則必須指定所有屬性的默認值
data class User(var name: String = "", var age: Int = 0)
複製(copying)
數據類在創建的時候,除了會生成上面的幾個方法外,還會生成一個copy
函數,
()copy()
能夠複製一個對象改變它的一些屬性情況下,又要保持其餘的不變,如上面的User
類,copy()
函數的實現:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
在使用copy()
之後,就可以修改數據類的一些屬性了:
val jack = User(name = "jack", age = 1)
val olderJack = jack.copy(age = 2)
Kotlin提供了Pair
和Triple
作爲標準數據類,命名數據類是更好的設計選擇。
兩個參數的時候使用Pair
數據類
三個參數的時候使用Triple
數據類