kotlin_屬性和字段的區別

屬性和字段

kotlin官方中文屬性和字段 傳送門

在java中 有類成員變量的定義,而且類成員變量可以只聲明不初始化(因爲在構造函數中java會給沒有初始化的成員變量,賦予默認值)

總述:
在面嚮對象語言中,一個類是有屬性和行爲的,在kotlin中與之對應的是屬性和方法,這裏我們詳細討論下屬性這個東西.屬性是一個類的某個特徵,這個特徵可能是可變的如年齡,也可能是不可變的如性別,我們在使用某個類的某個屬性時,我們不關心這個屬性時如果實現存儲的,我們關心的是 得到這個屬性的值,或者改變這個屬性的值,

在java中是用成員變量或者說是字段來表明屬性的,這個字段是存儲在棧中,但是在kotlin中,kotlin徹底封裝了屬性的獲取和設置,kotlin會爲每一個屬性都默認提供get和set方法(val只提供get方法),我們獲取某個屬性時,實際上就是調用這個get方法,設置屬性時就是調用set方法.屬性既然是通過get方法獲取的,那屬性可能僅僅是存在於get方法中,而不會存儲在棧中的某個變量中,比如我們設置一個val類型 num屬性,我們獲取該屬性的時候是通過其get方法即是: public final int getNum() { return 3; } 這個方法是直接返回3,所以num屬性並沒有存儲在某個變量中,僅僅是存儲在kotlin的代碼中,所以得到一個結論:在kotlin中類是有屬性的,但是一個屬性不一定對應着一個字段.

下面我們詳細的看下kotlin的屬性:

Person.Class

val age = 1  //不可變整形
var name = "張三" //可變String類型
注:這裏 age name都是屬性

這裏我們是聲明瞭2個屬性,一個是int型的age,一個是Stirng類型的name,而且age是不可變類型,name是可變類型的,這裏我們將上述2行代碼反編譯成java語言

 private final int age = 1;
 @NotNull
 private String name = "張三";
public final int getAge() {
  return this.age;
}
@NotNull
public final String getName() {
  return this.name;
}
public final void setName(@NotNull String var1) {
  Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
  this.name = var1;
}

這裏我們看到,kotlin聲明瞭2個字段,其中kotlin將val類型的int 聲明爲私有的不可變的類型(這也就是常說的val只讀,不可改變),而且自動提供了一個get方法.對於var類型的String 則聲明爲私有的沒有被final修飾,並且同時提供了get set方法

在kotlin中通過對象調用屬性時,實際上是調用get方法,賦值是調用set方法

int a = person.age;
這語句反編譯爲java爲
int a = person.getAge();
person.name = "lisi";
這句語句被反編譯爲
person.setName("lisi");

前面我們說到了kotlin中一個屬性不一定代表着一個字段,什麼意思呢(而前面我們反編譯屬性的聲明是有字段的呀):看下面代碼

var attention: String
    get() {
        return "ssss"
    }
    set(value) {
    }
val num: Int
   get() = 3

上面我們聲明瞭2個屬性一個 var可變的String類型的attention 另一個是val不可變的int類型的num,我們下面再看下其反編譯成java代碼的結果

 @NotNull
 public final String getAttention() {
  return "ssss";
  }

 public final void setAttention(@NotNull String value) {
  Intrinsics.checkParameterIsNotNull(value, "value");
  }

   public final int getNum() {
      return 3;
  }

我們注意到,反編譯成java代碼後,是沒有成員變量的(字段),我們接下來分析下爲什麼會這樣,

屬性是一個類的特徵,對於這個特徵我們需要獲取或者改變,在java中字段是屬性的實現方式,而並不是說屬性就是字段,在kotlin中屬性是用get和set方法實現的,所以在這個過程中,我們可以不用字段,直接使用get返回一個值用作屬性.但是在kotlin中真的沒有類似於java中字段這種東西嗎,答案是有的,只是在kotlin中叫做幕後字段,它是用來完善get set方法以實現屬性的功能.

在kotlin中,當get和set方法需要使用字段來實現屬性的功能時,編輯器會自動生成一個字段,該字段叫做幕後字段,並且該幕後字段可以在get和set方法使用field標識符來引用,比如

   var age = 2
    get() {
        return if (field >=0) {
            field
        } else {
            -field
        }
    }
	 set(value) {
        field = 2 * value
    }

上述代碼中field就是存儲的幕後字段,所以我們得到的屬性age的值永遠都是大於0的, 在set方法中我們看到幕後字段存儲的值是設置的值的2倍,這裏屬性和字段相同嗎,完全不同,所以說
幕後字段是實現屬性的一種手段,幕後字段不等於屬性,幕後字段和get set方法共同組成屬性

我們知道幕後字段是kotlin編輯器自動爲我們生成的,那生成的條件是什麼呢:官方說明是:
如果屬性至少一個訪問器使用默認實現,或者自定義訪問器通過 field 引用幕後字段,將會爲該屬性生成一個幕後字段。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章