Java中有可見性修飾符(private
...)祟滴,而Kotlin中也是有這樣的修飾符,但也有一些不一樣刀森,下面來學(xué)習(xí)Kotlin中的可見性修飾符(Visibility Modifiers)和數(shù)據(jù)類(Data Classes)的相關(guān)知識踱启。
可見性修飾符(Visibility Modifiers)
Kotlin有四種可見性修飾符,分別是public
研底、internal
埠偿、protected
和private
,默認的修飾符是public
榜晦,除了internal
之外冠蒋,其他三種修飾符與Java的訪問權(quán)限一樣。
Kotlin的可見性除了用于類乾胶,對象抖剿,接口,構(gòu)造函數(shù)识窿,屬性之外斩郎,還用于屬性的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中可以使用使用屬性名來直接獲取值和設(shè)置值的缩宜,原因就是Kotlin會自動生成屬性的get
和set
方法
但是,如果如果設(shè)置屬性的可見性是private
的話,我們知道private
修飾的是私有的锻煌,也就是當(dāng)前類可用妓布,那么就不會自動生成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也是不可見
}
注意:外部類不可以訪問內(nèi)部類的private
成員。
構(gòu)造函數(shù)同樣可以設(shè)置可見性捂龄,前面說過释涛,在設(shè)置主構(gòu)造函數(shù)的可見性或者注解的時候,要加上constructor
關(guān)鍵字倦沧。
class C @Inject private constructor(a: Int) { ... }
Kotlin中局部變量枢贿,函數(shù)和類是不允許使用修飾符的。
模塊(Modules)
internal
權(quán)限是是模塊級別的訪問權(quán)限刀脏,可以訪問本模塊的internal
變量和方法,當(dāng)跨模塊的時候就無法訪問另一個模塊的internal
變量或方法超凳。
數(shù)據(jù)類(Data Classes)
前面說過(Kotlin學(xué)習(xí)(五): 慣用語法和代碼風(fēng)格)愈污,Kotlin的慣用語法是有寫POJO類,一般寫那種類都是用data
修飾的類轮傍,也就是數(shù)據(jù)類表示暂雹,只保存數(shù)據(jù)的類。
data class User(val name: String, val age: Int)
編譯器自動從主構(gòu)造函數(shù)中聲明的所有屬性生成以下方法
可以看出有 getter
和setter
方法创夜,還有componentN()
函數(shù)杭跪,對應(yīng)按聲明順序出現(xiàn)的所有屬性,如name
就是component1()
驰吓,age
就是component2()
涧尿。
當(dāng)然還有 equals()
、hashCode()
檬贰、和 toString()
(輸出的格式為User(name=..., age=...)
)姑廉,為什么生成的class文件中沒有這三個類,但是又可以直接調(diào)用呢翁涤?
Any
類是Kotlin每個類的超類桥言,所以自然可以調(diào)用這幾個方法。
為了確保數(shù)據(jù)類生成的代碼的一致性和有意義葵礼,必須滿足
- 如果構(gòu)造函數(shù)參數(shù)中沒有聲明是
val
或者var
号阿,這些函數(shù)就不會生成 - 主構(gòu)造函數(shù)需要有至少一個參數(shù)
- 數(shù)據(jù)類不能有
abstract
、open
鸳粉、sealed
和inner
修飾 - 在1.1版本之前扔涧,數(shù)據(jù)類只能實現(xiàn)接口
在構(gòu)造函數(shù)那里也說過,如果生成的類需要一個無參數(shù)的構(gòu)造函數(shù)赁严,則必須指定所有屬性的默認值
data class User(var name: String = "", var age: Int = 0)
復(fù)制(copying)
數(shù)據(jù)類在創(chuàng)建的時候扰柠,除了會生成上面的幾個方法外粉铐,還會生成一個copy ()
函數(shù),copy()
能夠復(fù)制一個對象改變它的一些屬性情況下卤档,又要保持其余的不變蝙泼,如上面的User
類,copy()
函數(shù)的實現(xiàn):
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
在使用copy()
之后劝枣,就可以修改數(shù)據(jù)類的一些屬性了:
val jack = User(name = "jack", age = 1)
val olderJack = jack.copy(age = 2)
Kotlin提供了Pair
和Triple
作為標(biāo)準(zhǔn)數(shù)據(jù)類汤踏,命名數(shù)據(jù)類是更好的設(shè)計選擇。
兩個參數(shù)的時候使用Pair
數(shù)據(jù)類
三個參數(shù)的時候使用Triple
數(shù)據(jù)類