Get/Set
使用「物件.屬性」語法,表面上好像是直接存取物件變數的值。但在kotlin其實是去調用 get()及set()方法。每個物件變數都有自已的一組get及set。我們也可以覆寫這二個方法,只是若要覆寫的話,就不能使用主建構子產生物件變數,只能寫於類別內,而且必需給予初始值,其原因如下
fun main(args:Array<String>){
var p1=Pokemon(1, 2)
p1.level=1
println(p1.level)
}
class Pokemon constructor(var a:Int, var b:Int){
var level:Int=1//一定要初始化
get(){
println("返回level的值")
return field
}
set(v){
println("設定level, 並放大10倍")
field=v*10
}
/* 在這邊初始化無效
init{
this.level=1
}
*/
}
結果
設定level, 並放大10倍
返回level的值
10
上述主程式中,明明是 p1.level=1,但其值確是放大10倍,就代表了調用了set(v)方法。get()及set()必需立即置於物件變數之下,get()不能有參數,但一定要有return。set(v) 一定要有參數,且不能有return。
即然要覆寫get及set時一定要置於物件變數之下,那麼也就只有將物件變數宣告於類別之內才有機會。若使用主建構子宣告物件變數,那就沒有任何機會了。
另外在get及set裏,field 是一個關鍵字, 代表著本變數的意思
權限
物件變數的權限,預設(也就是沒寫權限修飾子)是public。另一個權限為private, 其範圍涵蓋整個類別。所以如果在物件變數前面加上private,則禁止在類別之外進行存取。
fun main(args:Array<String>){
var p1=Pokemon(1, 2)
/* 不可存取get及set
p1.level=1
println(p1.level)
*/
}
class Pokemon constructor(var a:Int, var b:Int){
private var level:Int
init{
this.level=1
}
}
物件變數既然被private禁止存取,那要如何控制呢? 此時就必需再加入 public 方法進行存取,此行為稱為封裝。
fun main(args:Array<String>){
var p1=Pokemon(1, 2)
p1.setLevel(100)
println("p1 level為 ${p1.getLevel()}")
}
class Pokemon constructor(var a:Int, var b:Int){
private var level:Int
init{
this.level=1
}
fun setLevel(level:Int){
if (level<0)this.level=level
else this.level=1
}
fun getLevel():Int{
return level
}
}
結果:
p1 level為 1
到目前為止,在物件變數前面加入private後,get及set權限都被禁止,這跟Java的機制是一樣的。
但如果覆寫get及set時,就可以禁止set,但開啟get的功能。現在終於知道為什麼kotlin要這麼囉嗦的使用get及set二個方法了。
請注意,set的權限不可高於get,而get必需跟物件變數的權限一樣。也就是說,set可以為private,get只能為 public。
fun main(args:Array<String>){
var p1=Pokemon(1, 2)
p1.setLevel(8)
println("p1 level為 ${p1.level}")
}
class Pokemon constructor(var a:Int, var b:Int){
var level:Int=1
private set
fun setLevel(level:Int){
if(level<10)this.level=level
else this.level=1
}
}
結果:
p1 level為 8
Internal
kotlin還有另一個權限,稱為internal,其範圍涵蓋當前的模組,所以比public的範圍還小,但比private大。但目前還沒提起模組,所以此權限日後再說明。
setXXX/getXXX
寫過Java的人,都習慣會使用 setXXX/getXXX。但如果用在kotlin的話,當物件變數為public, 那麼如下紅色部分,馬上就死給你看。
你可以寫成 setLe/getLe,但就是不能寫成完整的 setLevel/getLevel。原因是物件變數下的 get/set其實就是調用 jar的setLevel/getLevel。此時我們若又手動覆蓋系統的 setLevel/getLevel,系統就提出抗議了。
那為何本篇一開始可以用setLevel/getLevel呢? 那是因為物件變數設成 private。
class Pokemon{
var level:Int=1
fun setLevel(l:Int){
this.level=l
}
fun getLevel():Int{
return this.level
}
}
I’m amazed by your capacity to turn even the most common topics into engaging content. Well done to you!