[ Kotlin 小撇步 #4] 你該知道的 Data Class 小知識

Andy Lu
5 min readApr 30, 2021
Data Class mindmap

Data Class 是很多人由 Java 轉換成 Kotlin 中,最先開始使用的類別。 為什麼 Data Class 可以成為 Java 轉換成 Kotlin 的起手式呢? 讓我們看下去 🏃‍♂️

從 Java 的類別開始說起

當我們需要定義物件的時候,如果是在 Java 中,我們需要自行定義 setter() 以及 getter(),如下類別,如果我們有一個 Student 的類別,其屬性有兩個 一個為 Name 另一個為 Age,在 Java 我們會這樣定義:

Class Student in Java
  1. 定義一個傳入 Name 以及 age 的建構式。
  2. 針對屬性 Name 以及 Age 分別定義其 getter()。(視情況決定是否需要 setter())。

那麼,我們就可以將資料存在該類別中。

使用 Java 的類別建立相同內容的物件時,雖然內容相同,但是因為在記憶體的位置是不同的,所以比對的結果就是 false 。

除非覆寫 (override) equals() 函式,來達成想要的比對結果。

回來看看 Kotlin 的資料類別 (data class)

data class 主要解決兩個重要問題:

  1. setter()getter() 太惱人。
  2. 比對兩個具有相同的物件內容時,會回傳 false。在 Java 中,甚至在 Kotlin 的類別中也會有同樣的現象。

如何定義 data class?

一行解決😁

  • 在 上面範例的 data class 建構式中,不知道有沒有人注意到,我在這邊使用的是 val
  • 使用 val 的意義就是這個屬性是不可變動的,而這也是 Kotlin 所希望我們做的,所以在這邊就不會自動產生 setter()

到目前為止,我們知道 data class 幫我們解決了:

  1. 冗余的 setter()getter()
  2. 相同的物件內容的比對是回傳 true,而不是 false。

將 data class 轉成 Java 看看

跟原本 Java 的程式碼相比,我們發現有些地方不一樣。

  1. 分別覆寫了: toString()hashCode()equals() 函式。
  2. 新增了 copy() 函式。
  3. 多了 component1(), component2() 函式。

1. 分別覆寫了: toString()hashCode()equals() 函式。

覆寫 equals() 函式

在第一段的 Java 程式碼後面,我們覆寫了 equals() 函式,讓類別內容相同的物件可以會回傳 true,而在 data class 的 equals() 中,更是直接在背後覆寫了equals() 函式,所以我們比對兩個物件的時候,就會回傳 true 。

覆寫 hashCode() 函式

equals() 的內容是將物件中每一個屬性都拿來做比較,如果內容是複雜的物件,那麼比對的時間就會比較長,所以 data class 另外也覆寫了 hashCode(),當要比對兩個物件是否相同時,只要比對兩個物件之間的 hashCode()是否相等,如果相等,那就代表這兩個物件內容是相等的,就不需要針對每一個物件的屬性去做比較,可以節省很多比對時間。

覆寫 toString() 函式

data class 還很貼心的將 toString() 也一併覆寫了,可以產生更易懂的 toString(),因為把所有屬性的值都一併印出來了。至於原本的 toString() 有多不易懂,讀者可以自行試試看 XD

2. 新增 copy() 函式

data class 另一個厲害的地方是,它提供了 copy() 函式,利用它,當我們需要物件的副本時,我們就可以輕鬆產生,更不用說它還包含了替換裡面屬性的功能。

可以直接將物件複製一份,而不需要使用建構式的方式產生。

上面有提到,可以在複製時順便替換屬性的值。

3. 多了 component1(), component2() 函式

data class 會根據屬性的數量新增 componentN() 的函式,這個函式有什麼用處呢?

利用 componentN(),Kotlin 就知道每個屬性的順序,那麼我們就可以一口氣的將所有的屬性解構(Destructuring)

Destructuring

我們發現,Kotlin 將 data class 解構成兩個變數。注意到,這邊是用括弧來將所有的變數括起來的。

那麼,原本的類別有這樣的功能嗎?可以請讀者自行試試看。

data class 的屬性可以是另外的 data class 嗎?

可以的,data class 也是一個類別,可以當作屬性傳進去。

下面範例,新增一個 Classroom data class ,其中包含兩個屬性一個是 Student ,另一個則是 Grade (年級)

可以得知,無論怎麼比,就算是 data class 作為屬性帶入,只要內容相等,那麼結果就會是 true。(畢竟 data class 的 equals() 就比對屬性的值)

如果用 === 比較呢?

大家可以猜猜看,前面的 == 如果換成 === 會是什麼結果呢?

給大家一個提示,每次產生的值,都會使用不同的記憶體區塊。

.

.

.

.

答案是 false,因為佔用不同的記憶體位置。

小結

data class 資料類別,不愧是 Java 轉 Kotlin 的起手式,簡單的一個關鍵字 data 加上去,就不需要產生 setter()getter(),也自動幫我們覆寫了 equals(),方便我們針對兩個相同內容的物件做比較。

而在 data class 中新增的函式:( copy(), componentN()),更是讓 data class 的方便性更加提高。可以輕鬆的產生一份複製的物件,也可以直接由實體物件解構出其參數。

如果你想由Java 轉換至 Kotlin, data class 絕對可以是你的起手式。

本篇文章如果有幫助到你,請拍手👏鼓勵我吧~ 小祕技:拍手按鈕按著可以連續拍喔。

--

--

Andy Lu
Andy Lu

Written by Andy Lu

Android/Flutter developer, Kotlin Expert, like to learn and share.

No responses yet