iT邦幫忙

2026 iThome 鐵人賽

DAY 6
1

配合分支:day06/start,Repo: 按我

知道資料流的觀念後,本章進入程式碼結構基礎介紹。前一則笨問題發現是數值塞錯地方造成的問題。完成「新增照片」的表格後 DiaryForm 會啟動一個 callback function,將標題及內文帶回呼叫點。

儲存時發生了什麼事情?

https://ithelp.ithome.com.tw/upload/images/20260825/20141615PL09sY8JmH.png

DiaryEntry 看起來展開一樣塞進資料,並加到 entries 列表之中。先來看看 DiaryEntry 是什麼東西。在 Android Studio 裡頭,用 Cmd + B (Windows/Linux: Ctrl + B) 前往這個東西的實作。

https://ithelp.ithome.com.tw/upload/images/20260825/20141615bXHOB6N3xM.png

這東西是一個 data class!和 MainActivity 有什麼差異?它也有 class。 🤔 一般來說,class (中文翻譯是類別,中國翻成「類」) 像是一個規格書。注意到 class 裡頭有很多 function (函式) 可以做事,可以存變數紀錄狀態。

一般來說 class 可以透過建構子 (Constructor) 將它實作出來用,像是:

class Car {
    // ... 省略
}

可以這樣把它召喚出來:Car()。 此數,能用一個變數將它接起來:

val car = Car()

透過建構子得到的東西,叫做 Instance (翻譯是:實例),反正你會得到一個 Instance,可以操弄它。

不過這裡也提醒 MainActivity來自 Android 的元件,他有自己的建構方式,所以在照片日記裡頭看不到他的建構子。(aka. 無法透過 MainActivity() 得到一個 Instance)

val vs var

不過前面不是提到變數是 var abcde = <數值> 嗎?這裡出現了 val
兩者的差異是 val 一開始賦予數值後,就無法更改了。但是 var 可以改!

val name = "RayLiu"
name = "RayYuan"    // 🥲 不能改

// vs

var name = "RayLiu"
name = "RayYuan"    // 成功!改成 "RayYuan"

雖然 var 很方便,不過出問題時要找也非常麻煩,要確認到底哪邊會把數值改掉。經過前兩次的教訓,在一個實務上在跑的系統裡,用 var 要追查問題絕對是更為複雜的!

val 因為只有賦予數值一次,之後只要去查資料流怎麼流動就行了。現代的程式開發也建議絕大多數的情境,用 val 就好了!

data class

回到 class 的話題:畫面上有三篇日記。它們都有標題、內容、心情。這三篇日記是三種不同的東西,還是同一種東西的三個實例?

答案是後者。DiaryEntry 是「日記這種東西」的規格,實際建立出的每一篇日記才是物件。所以在 DiaryForm 回傳時,可以這樣子接住實例,並塞到列表裡頭。

https://ithelp.ithome.com.tw/upload/images/20260825/20141615zGzpM2UrTa.png

啊,你可能覺得覺得很怪,為什麼還要塞到一個新的列表裡頭,再加入 entries 裡頭。

entries = listOf(newEntry) + entries

註:listOf(物件...) 會吐出物件的列表:List<物件>
是因為要把這個新加入的日記放在最前面(也就是最上面),如果沒有要這樣做,放最後面,那直接:

entries = entries + newEntry

就好。
那 data class 差別到底是什麼?data class 其實是 Kotlin 的語法糖 :-P ,提供一些好東西。比如說要複製一篇照片日記:

// 假設 要複製 oldEntry
val newEntry = DiaryEntry(
	photoResId = oldEntry.protoResId,
	title = oldEntry.title,
	note = oldEntry.note,
	mood = "亢奮",    // <== 改了這個,其他一樣
	createdAt = oldEntry.createdAt
)

data class 只需要:

val newEntry = oldEntry.copy(mood = "亢奮")

// 沒有要改亢奮,就直接 copy 就好

val newEntry = oldEntry.copy()

非常爽。當然不只這些,總之 data class 已經對傳遞資料做了各種好用的處理,總之需要傳遞資料時,記得想到他。

class vs data class

  • 「這個東西的主要責任是保存與傳遞資料嗎?」是的話,優先考慮 data class
  • 「這個東西還要負責行為、流程或規則嗎?」那就用一般 class

Properties

就是黏在 class 上的變數,例如:

class Car {
    // 👇🏼 這些黏在 class 上的變數,即是 properties
    private val name = "Toyota"
    var price = 600000
    private val isGas = true
}

或是建構的時候需要帶的:

class Car(
    private val year: Int // 👈🏼 這也是
) {
    private val name = "Toyota"
    var price = 600000
    private val isGas = true
}

data class 裡頭的這些也是:

data class DiaryEntry(
    // 👇🏼 這些也是 properties
    val title: String,
    val note: String,
)

這些 class 被 initialize (中文好像是:實例化,也就是上面說的召喚出來,通常工程師會說 Init )後,可以透過變數存取它。例如改價格 (ㄏ)

val car = Car(year = 2022)
car.price = 777  // 👈🏼 可以這樣存取 properties,如果是 var 就能改

註:出現了第三個 Type: Int,一般來說就是拿來存數字的。
而存取 properties 前幾天我們已經示範過囉!就是像這樣 car.title 取資料。

TL;DR

  • class(類別):像規格書,裡面可以放 function 做事、用變數記狀態;今天的日記不是三種不同的東西,而是同一份規格做出來的。
  • 建構子(Constructor):用 Car() 這種寫法把 class 召喚出來;沒有這一步,寫好的規格還不能拿來用。
  • Instance(實例):建構子做出來的那一份東西,例如 val car = Car();畫面上三篇日記就是三個實例。
  • val:一開始賦值後就不能改;出問題時只要追資料怎麼流,不必猜哪裡被改掉。
  • var:可以一直改數值,追查「到底哪邊把數值改掉」會很麻煩,所以能用 val 就用 val
  • data class:Kotlin 專門拿來裝資料的 class;DiaryEntry 就是日記的規格。
  • listOf:會吐出物件的列表 List<物件>
  • copy:data class 的複製寫法,只要改想改的欄位,例如 oldEntry.copy(mood = "亢奮"),不必把每個欄位重抄一遍。
  • class vs data class:負責行為、流程或規則才用一般 class;只有保存與傳遞資料才用 data class
  • Properties:黏在 class 上的變數(含建構時帶入的);Init 後用 car.price 這種寫法存取,var 的才能改。

上一篇
[Day05] 資料流與變數
系列文
我的第一個手作りAndroid App!快樂學習物件導向程式設計!6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
chiaominchang222
iT邦新手 5 級 ‧ 2026-08-25 18:47:44

為什麼可以這麼快完成day6!

我要留言

立即登入留言