set get

屬性位置

屬性是放在類別中。

class 類別名 {
  var 屬性名: 屬性類型 = 初始值
  val 屬性名: 屬性類型 = 初始值

  // 屬性是空值類型,可指派空值,空值類型是var,因為要修改null值
  var 屬性名: 屬性類型? = null
}

field get() set(value)

Kotlin會自動為屬性產生field, get(), set(value)方法。

1
var name = "Alex"

預設會自動變成下面的程式碼。

1
2
3
4
5
var name = "Alex"
    get() = field  
    set(value) {
        field = value    
    }

field

field儲存屬性值在記憶體中,如果要使用get()讀取屬性值,或用set()更新屬性值,需要使用field來讀取或更新,field只能在get()方法跟set()方法使用。

為什麼要使用field?因為Java都要自己寫set(), get(), this.屬性 = 參數,this用的太多,簡化成用field省略大量程式碼。

覆寫get()方法

get()是讀取屬性,先前的內容說明get()會自動產生,但也可以自己覆寫。

覆寫get()方法,field代表name,把name轉成全大寫。

覆寫語法1

var 變數: 類型 = 初始值
    get() {
      // 要記得加上return
      return 回傳值
    }
1
2
3
4
5
6
class Student {
    var name: String? = null
        get() {
            return field?.uppercase()
        }        
}

覆寫語法2

var 變數: 類型 = 初始值
    get() = field
1
2
3
4
class Student {
    var name: String? = null
        get() = field?.uppercase()
}

覆寫set(value)方法

set(value),是更新屬性,先前的內容說明set()會自動產生,但也可以自己覆寫。

語法,value為傳進來的參數。

var 變數: 類型 = 初始值
    set(value) {
      field = value    
    }

trim()去掉前後空白,再把value指派到field,field代表name屬性。

1
2
3
4
5
6
7
class Student {
    var name: String? = null
        get() = field?.uppercase()
        set(value) {
            field = value?.trim()
        }
}

var與val

var才能修改屬性,才會有set()更新方法。

val只能讀取,不能修改,不會有set()更新方法,只有get()讀取。

set(value)只能用field

set(value)方法中,不能用屬性名稱。

value參數指派給屬性名(例如name),程式碼就會進入無限迴圈。

1
2
3
4
5
6
7
8
class Student {
    var name: String? = null
        get() = field?.uppercase()
        set(value) {
            // 不能這樣寫,不能把value指派給屬性名
            name = value?.trim()
        }
}

覆寫可單獨只寫set()或get()

不用同時覆寫set()與get()

以下只覆寫set()

1
2
3
4
5
6
class Student {
    var name: String? = null
        set(value) {
            field = value?.trim()
        }
}

測試

1
2
3
4
5
6
7
8
9
10
11
12
class Student {
    var name: String? = null
        get() = field?.uppercase()
        set(value) {
            field = value?.trim()
        }
}
fun main() {
    var student = Student()
    student.name = "     Bill      "
    println(student.name)
}
BILL

不使用field覆寫get()

建立一個randomId屬性,每次都取得不同的值,不使用field,也是可以覆寫get()

1
2
3
4
5
6
7
8
class Student {
    val randomId
        get() = (1 .. 100).shuffled().first()  // 取出亂數
}
fun main() {
    var student = Student()
    println(student.randomId)
}
22

set()作為檢查的機制

指派給 speakerVolume 屬性的值介於 0 到 100 之間。

可以在 set() 函式中使用 in 關鍵字,並在後面加上值的範圍,以檢查 Int 值是否介於 0 到 100 的範圍內。如果該值在預期範圍內,系統會更新 field 值,否則屬性的值維持不變。

1
2
3
4
5
6
var speakerVolume = 2
    set(value) {
        if (value in 0..100) {
            field = value
        }
    }

存取權限

若set前面加上private,代表不允許其它地方設值,只有本身的類別可以設值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Cat4 (_name: String, _age: Int) {
    var name:String = ""
        private set(value) {
            field = value
        }
    var age:Int = 0
    init {
        name = _name
        age = _age
    }
}
fun main() {
    val cat4 = Cat4("喵喵", 2)
    println(cat4.name)
    println(cat4.age)
    // 以下會編譯失敗
    cat4.name = "Momo"
}

Java原始碼

var非空值屬性

Student類別中有一個var屬性。

1
2
3
class Student {
    var name = "Alice"
}

NotNull與checkNotNullParameter()

看產生的java檔,Decompile轉成Java檔

可以發現自動產生getName()、setName(),\@NotNull是kotlin的Annotation,目的是檢查屬性、傳回值、參數是否為null,Annotation的作用在於檢查,發現是null,產生編譯例外。

checkNotNullParameter()方法是檢查是否為空值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public final class Student {
   @NotNull
   private String name = "Alice";

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      // checkNotNullParameter()
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.name = var1;
   }
}

修改屬性為Bill

1
2
3
4
5
6
7
class Student {
    var name = "Alice"
}
fun main() {
    var student = Student()
    student.name = "Bill"
}

Java程式檔,發現已經自動產生setName("Bill")

1
2
3
4
5
public final class ClassTestKt {
   public static final void main() {
      Student student = new Student();
      student.setName("Bill");
   }

屬性為空值類型

把name屬性改成空值類型。

1
2
3
4
5
6
7
class Student {
    var name: String? = null
}
fun main() {
    var student = Student()
    student.name = "Bill"
}

Nullable 與 checkNotNullParameter()

Java程式碼,\@Nullable代表可為空值。

1
2
3
4
5
6
7
8
9
10
11
12
13
public final class Student {
   @Nullable
   private String name;

   @Nullable
   public final String getName() {
      return this.name;
   }

   public final void setName(@Nullable String var1) {
      this.name = var1;
   }
}

可為空值類型,產生出來的Java檔,就沒有checkNotNullParameter()方法。

1
2
3
4
   public static final void main() {
      Student student = new Student();
      student.setName("Bill");
   }

results matching ""

    No results matching ""