2017-04-05 49 views
36

作爲一名Java開發人員,後臺字段的概念對我來說有點陌生。鑑於:什麼是科特林支持領域?

class Sample { 
     var counter = 0 // the initializer value is written directly to the backing field 
     set(value) { 
      if (value >= 0) field = value 
     } 
    } 

這是什麼支持領域的好處? Kotlin docs說:Kotlin中的類不能有字段。但是,有時在使用定製訪問器時需要有後臺字段。爲什麼?在setter中使用屬性名稱本身的區別是什麼,例如。

class Sample {   
     var counter = 0 
     set(value) { 
      if (value >= 0) this.counter = value // or just counter = value? 
     } 
    } 
+3

當然,作爲Java開發人員,這個概念是每天使用一百萬次的東西:)所有這些'private SomeClass字段;' – Strelok

+4

在setter中使用屬性本身會導致無限遞歸,因爲將一些值賦給屬性會一直打電話給二傳手。 – funglejunk

+0

@Strelok我的不好....我在假設閱讀Kotlin的文檔時'this.counter = value'與Java相同。 –

回答

36

因爲,說如果你沒有field關鍵字,您將無法實際設置/獲取在get()set(value)值。它使您能夠訪問自定義訪問器中的後臺字段。

這是你的樣品相當於Java代碼:

class Sample { 
    private int counter = 0; 
    public void setCounter(int value) { 
     if (value >= 0) setCounter(value); 
    } 
    public int getCounter() { 
     return counter; 
    } 
} 

顯然,這是不好的,因爲二傳手只是一個infinte遞歸到自身,從來沒有改變任何東西。每當你寫入foo.bar = value時,請記住在kotlin中,它將被翻譯爲setter調用而不是PUTFIELD


編輯:科特林具有性質而Java有字段,這是比場相當更高層次的概念。

有兩種類型的屬性:一種帶有後臺字段,另一種沒有。

具有後臺字段的屬性將以字段的形式存儲該值。該領域使存儲在內存中的價值成爲可能。此類屬性的一個示例是Pairfirstsecond屬性。該屬性將改變Pair的內存中表示。

沒有後臺字段的屬性必須以其他方式存儲它們的值,而不是直接將其存儲在內存中。它必須從其他屬性或對象本身進行計算。此屬性的一個示例是Listindices擴展特性,該特性不支持字段,而是基於size屬性的計算結果。所以它不會改變List的內存表示(它根本無法完成,因爲Java是靜態類型的)。

+0

感謝您的回答!我的壞...我假設'this.counter = value'與java等價。 –

7

備份字段非常適合在狀態更改時運行驗證或觸發事件。想想您將代碼添加到Java setter/getter的時間。在類似的情況下,備份字段會很有用。當你需要控制或對setter/getters有可見性時,你會使用後備字段。

當爲字段賦予字段名稱本身時,實際上是調用setter(即set(value))。在你的例子中,this.counter = value會遞歸到set(value)中,直到我們溢出堆棧。使用field可繞過setter(或getter)代碼。

1

最初,我也很難理解這個概念。所以讓我在一個例子的幫助下向你解釋。

考慮這個科特林級

class DummyClass { 
    var size = 0; 
    var isEmpty 
     get() = size == 0 
     set(value) { 
      size = size * 2 
     } 
} 

現在,當我們在看代碼,我們可以看到它有2個屬性即 - size(默認存取)和isEmpty(自定義訪問器)。但它只有1個字段,即size。要理解它只有1個字段,讓我們看看這個類的Java等價物。

轉到工具 - > Kotlin - >在Android Studio中顯示Kotlin ByteCode。點擊反編譯。

public final class DummyClass { 
    private int size; 

    public final int getSize() { 
     return this.size; 
    } 

    public final void setSize(int var1) { 
     this.size = var1; 
    } 

    public final boolean isEmpty() { 
     return this.size == 0; 
    } 

    public final void setEmpty(boolean value) { 
     this.size *= 2; 
    } 
} 

顯然,我們可以看到,在Java類只有getter和setter函數爲isEmpty,並沒有宣佈它領域。同樣在Kotlin中,由於該屬性完全不依賴於該字段,因此沒有屬性isEmpty的後臺字段。因此沒有支持領域。


現在讓我們刪除isEmpty屬性的自定義getter和setter。

class DummyClass { 
    var size = 0; 
    var isEmpty = false 
} 

和Java當量的上述類是

public final class DummyClass { 
    private int size; 
    private boolean isEmpty; 

    public final int getSize() { 
     return this.size; 
    } 

    public final void setSize(int var1) { 
     this.size = var1; 
    } 

    public final boolean isEmpty() { 
     return this.isEmpty; 
    } 

    public final void setEmpty(boolean var1) { 
     this.isEmpty = var1; 
    } 
} 

這裏我們可以看到兩個領域sizeisEmptyisEmpty是後臺字段,因爲isEmpty屬性的獲取器和設置器取決於它。