Kotlin 知識梳理(4) 數據類、類委託 及 object 關鍵字

1、本文概要

本文是對<<Kotlin in Action>>的學習筆記,若是須要運行相應的代碼能夠訪問在線環境 try.kotlinlang.org,這部分的思惟導圖爲: 框架

2、數據類和類委託

2.1 數據類:自動生成通用方法的默認實現

在平時的開發中,咱們每每會使用許多的xxBean對象用做數據容器,而在定義這些對象時,通常會重寫它的如下三個方法:函數

  • equals:用來比較實例
  • hashCode:用來做爲例如HashMap這種基於哈希容器的類
  • toString:用來爲類生成按聲明順序排列的全部字段的字符串表達形式

Kotlin中,只須要爲你的類添加data關鍵字,以上這些必要的方法就會自動生成好,例以下面的例子,咱們演示了以上三個方法的做用: 學習

運行結果爲:

equalshashCode方法會將全部在主構造方法中聲明的屬性歸入考慮:設計

  • equals方法會檢測全部的屬性的值是否相等
  • hashCode方法會返回一個根據全部屬性生成的哈希值

數據類和不可變性

在設計數據類時,應當儘可能只使用只讀的屬性,讓數據類的實例不可變,由於若是不這樣,被用做鍵的對象在加入HashMap或者相似容器後被修改了,容器會進入一種無效的狀態。3d

爲了讓使用不可變對象變得容易,Kotlin編譯器爲它們生成了copy方法,並在copy的同時修改某些屬性的值,copy出來的副本有着單獨的聲明週期並且不會影響代碼中引用原始實例的位置,使用方法以下: code

2.2 類委託

當咱們須要向一個類添加一些行爲時,通常有兩種作法:cdn

  • 繼承這個類,在子類中增長方法 這種方法的缺點是:當系統不斷演進而且基類的實現被修改或者新方法被添加進去時,你作出的關於類的行爲的假設會失效。
  • 使用裝飾器模式 本質是建立一個新類,實現與原始類同樣的接口並將原來的類的實例做爲一個字段保存。與原始類擁有一樣行爲的方法不用修改,只須要直接轉發到原始類的實例。這種方法的缺點是:須要至關多的樣板代碼。

Kotlin將委託做爲一個語言級別的功能作了頭等支持。不管何時實現一個接口,你均可以使用by關鍵字 將接口的實現委託到另外一個對象;當須要修改某些方法的行爲時,能夠重寫它們,這樣你的方法就會被調用而不是使用生成的方法,能夠保留感到滿意的委託給內部的實例中的默認實現。 對象

運行結果爲:

3、object 關鍵字

object關鍵字在多種狀況下出現,它的核心理念爲:這個關鍵字 定義一個類並同時建立一個實例,下面咱們介紹它的三個應用場景:blog

  • 對象聲明 是定義單例的一種方式
  • 伴生對象 能夠持有工廠方法和其它與這個類相關,但在調用時並不依賴類實例的方法,它們的成員能夠經過類名來訪問。
  • 對象表達式 用來替代Java的匿名內部類。

3.1 對象聲明:建立單例易如反掌

Java中,單例模式一般是使用private構造方法,而且用靜態字段來持有這個類僅有的實例。繼承

而在Kotlin中,經過使用對象聲明功能,將類聲明與該類的單一實例聲明結合到了一塊兒。

  • 對象聲明經過object關鍵字引入,一個對象聲明能夠很是高效地以一句話來定義一個類和一個該類的變量。
  • 一個對象聲明能夠包含屬性、方法、初始化語句塊等的聲明,可是 不容許聲明構造方法,這是由於對象在定義的時候就已經建立了,不須要在其餘地方調用構造方法。
  • 對象聲明容許使用對象名加.字符的方式來調用方法和訪問屬性。

繼承自接口的對象聲明

對象聲明能夠繼承自類和接口,這一般在你使用的框架須要去實現一個接口,可是你的實現不包含任何狀態的時候頗有用。

在類中聲明對象

在類中使用對象聲明時,這樣的對象一樣只有一個單一實例:它們在每一個容器類的實例中具備相同的實例。

運行結果爲:

在 Java 中使用 Kotlin 對象

若是要在Java中使用Kotlin中的聲明對象,能夠經過訪問靜態的INSTANCE字段:

Kotlin 中的對象聲明
Java 的調用方式

3.2 伴生對象:工廠方法和靜態成員的地盤

Kotlin的類不能擁有靜態成員,做爲替代,Kotlin依賴包級別函數(在大多數情形下可以替代Java的靜態方法)和對象聲明(在其餘狀況下替代Java的靜態方法,同時還包括靜態字段),在大多數狀況下,推薦使用頂層函數,可是頂層函數不能訪問類的private變量。

所以,若是你須要寫一個 在沒有類實例的狀況下 調用可是須要 訪問類內部的函數,能夠將其寫成那個類中的 對象聲明的成員

在類中定義的對象之一可使用一個特殊的關鍵字來標記 companion,若是這樣作,就得到了直接 經過容器類名稱來訪問這個對象的方法和屬性的能力,再也不須要顯示地指明對象的名稱,下面是一個基礎的示例:

運行的結果爲:

使用工廠方法建立對象

下面是使用伴生對象來實現工廠方法的例子:

3.3 做爲普通對象使用的伴生對象

伴生對象是一個聲明在類中的普通對象,它能夠有名字,實現一個接口或者有擴展函數或屬性。假設咱們須要在對象和JSON之間進行序列化和反序列化,能夠將序列化的邏輯放在伴生對象中。

運行結果爲:
在大多數狀況下,經過包含伴生對象的類的名字(也就是例子中的 Person類)來引用伴生對象,因此沒必要關心它的名字,若是省略了伴生對象的名字,默認的名字將會分配爲 Companion

在伴生對象中實現接口

就像其它對象聲明同樣,伴生對象也能夠實現接口,能夠將包含它的類的名字當作實現了該接口的對象實例來使用。

運行結果爲:

伴生對象擴展

Kotlin 知識梳理(2) - 函數的定義與調用 中,咱們介紹了經過擴展函數,能夠經過代碼庫中其它地方定義類實例調用的方法,可是若是你須要定義能夠經過 類自身調用的方法,就像伴生對象方法或者Java靜態方法該怎麼辦呢?

舉例來講,若是類有一個伴生對象,能夠經過在其上定義擴展函數來作到這一點,即類C有一個伴生對象,而且在C.Companion上定義了一個擴展函數func,則能夠經過C.fun()來調用它。

下面,咱們爲Person類的伴生對象定義一個擴展函數:

當調用toJson就像是它是一個伴生對象定義的方法同樣,可是實際上它是做爲擴展函數在外部定義的。而爲了可以爲你的類定義擴展,必須在其中聲明一個對象,即便是空的。

3.4 對象表達式:改變寫法的匿名內部類

object關鍵字不只可以用來代表單例式的對象,還能用來聲明 匿名對象,它替代了Java中匿名內部類的用法。例如,讓咱們來看看怎樣將一個典型的匿名內部類用法轉換成Kotlin

運行結果爲:

將匿名對象存儲到變量中

除了去掉對象的名字外,語法與對象聲明相同的。對象表達式聲明瞭一個類並建立了該類的一個實例,可是沒有給這個類或是實例分配一個名字。一般來講,它們都是不須要名字的,由於你會將這個對象用做一個函數調用的參數。若是你須要給對象分配一個名字,能夠將其存儲到一個變量中:

在對象表達式中修改變量的值

Java的匿名類同樣,在對象表達式中的代碼能夠訪問建立它的函數中的變量,可是與Java不一樣,訪問並被限制在final變量,還能夠在對象表達式中修改變量的值。
運行結果爲:

更多文章,歡迎訪問個人 Android 知識梳理系列:

相關文章
相關標籤/搜索