Kotlin Tutorial(10)函式 << 前情
封裝是物件導向程式設計一個基礎的特性,應用程式需要的資料與功能,通常會封裝為類別,使用類別建立的物件,可以大幅度簡化應用程式的設計,後續的修改與功能擴充,也都會簡單多了。
宣告應用程式需要的類別
一般的應用程式通常需要一些資料,例如下面這個瀏覽與管理記事資料的App,每一個記事資料可以儲存使用者輸入的標題與內容:
對於應用程式來說,一個記事需要的資料,不應該是一些變數,而是一個封裝在類別裡面的屬性,每一個記事資料都是一個使用類別建立的物件。應用程式需要像這樣的資料,可以使用下面的語法宣告一個類別:
class 類別名稱 constructor(屬性變數宣告, ...)
屬性變數宣告的部份,根據這個類別需要的資料,使用下面的語法宣告不可以改變值的屬性變數,例如記事資料的編號:
使用下面的語法宣告可以改變值的屬性變數,例如記事資料的標題或內容:
宣告類別以後,就可以使用下面的語法,建立需要的物件,呼叫建構式建立物件的時候,必須根據類別的主要建構式宣告提供必要的參數:
val|var 變數名稱: 類別名稱 = 類別名稱(參數,...)
下面的範例程式宣告一個封裝記事的類別,類別名稱是Item01,每一個使用這個類別建立的物件,都會包含編號、標題與內容三個屬性變數:
/* net.macdidi5.kotlin.tutorial.ch11.Item01.kt */
package net.macdidi5.kotlin.tutorial.ch11
// 宣告包含id(編號)、title(標題)與content(內容)三個屬性的類別
// 為類別宣告主要建構式的參數,也同時宣告這個類別的屬性
class Item01 constructor (val id: Long,
var title: String,
var content: String)
fun main(args: Array<String>) {
// 宣告建立Item01物件,依照主要建構式的順序提供參數
val item01 = Item01(1, "Hello", "Hello Kotlin!")
println("Item01(id=${item01.id}, title=${item01.title}, content=${item01.content})")
// 顯示: Item01(id=1, title=Hello, content=Hello Kotlin!)
// 編譯錯誤,使用val宣告的屬性不可以修改
// item01.id = 11
// 設定title與content
item01.title = "Hello01"
item01.content = "Hello Kotlin 01!"
println("Item01(id=${item01.id}, title=${item01.title}, content=${item01.content})")
// 顯示: Item01(id=1, title=Hello01, content=Hello Kotlin 01!)
}
為屬性變數設定預設值
使用宣告好的類別建立物件的時候,需要根據屬性的宣告,設定物件所有屬性的值。不過應用程式在建立物件的時候,可能只需要設定部份屬性的值。例如建立一個記事資料,只需要設定編號與標題。
如果希望在建立物件的時候,可以設定部份需要的屬性值,使用下面的語法,在類別的屬性變數宣告加入預設值的設定:
val 屬性名稱: 屬性型態 = 預設值
var 屬性名稱: 屬性型態 = 預設值
下面的範例程式為類別的屬性加入預設值的宣告,可以在建立物件的時候,依照不同的需求設定屬性值:
/* net.macdidi5.kotlin.tutorial.ch11.Item02.kt */
package net.macdidi5.kotlin.tutorial.ch11
// 宣告包含id(編號)、title(標題)與content(內容)三個屬性的類別
// 主要建構式的constructor關鍵字可以省略
// 為title與content兩個欄位設定預設值
class Item02 (val id: Long = 0,
var title: String = "",
var content: String = "") {
// 宣告傳回資訊的函式
fun getDetails() = "Item02(id=$id, title=$title, content=$content)"
}
fun main(args: Array<String>) {
// 省略設定預設值的建構式參數title與content
val item0201 = Item02(201)
println(item0201.getDetails())
// 顯示: Item02(id=201, title=, content=)
// 省略設定預設值的建構式參數content
val item0202 = Item02(202, "Hi")
println(item0202.getDetails())
// 顯示: Item02(id=202, title=Hi, content=)
val item0203 = Item02(203, "Hi", "Hello")
println(item0203.getDetails())
// 顯示: Item02(id=203, title=Hi, content=Hello)
}
使用初始化區塊
為類別加入主要建構式以後,呼叫主要建構式建立的物件,根據提供的參數設定物件的 屬性值,如果需要檢查參數的正確性,或是根據屬性的應用執行額外的處理,可以在類別加入初始化區塊執行這類工作:
/* net.macdidi5.kotlin.tutorial.ch11.Item02.kt */
package net.macdidi5.kotlin.tutorial.ch11
// 宣告包含id(編號)、title(標題)與content(內容)三個屬性的類別
// 主要建構式的constructor關鍵字可以省略
// 為title與content兩個欄位設定預設值
class Item02 (val id: Long = 0,
var title: String = "",
var content: String = "") {
// 初始化,可以在這裡檢查與處理屬性值
init {
title = if (title.isEmpty()) "Title required" else title
content = if (content.isEmpty()) "Content required" else content
}
// 宣告傳回資訊的函式
fun getDetails() = "Item02(id=$id, title=$title, content=$content)"
}
初始化區塊會在主要建構式接收參數並設定好屬性以後執行:
val item0203 = Item02(203, "Hi", "Hello")
println(item0203.getDetails())
// 顯示: Item02(id=203, title=Hi, content=Hello)
val item0204 = Item02(204, "", "")
println(item0204.getDetails())
// 顯示: Item02(id=204, title=Title required, content=Content required)
建立與使用物件陣列
需要處理多個物件的時候,如果個數是固定的,使用陣列是比較合適與建單的。下面的語法可以建立一個儲存多個物件的陣列:
下面的範例程式示範使用陣列儲存與使用多個記事物件:
/* net.macdidi5.kotlin.tutorial.ch11.Item02.kt */
package net.macdidi5.kotlin.tutorial.ch11
// 宣告包含id(編號)、title(標題)與content(內容)三個屬性的類別
// 主要建構式的constructor關鍵字可以省略
// 為title與content兩個欄位設定預設值
class Item02 (val id: Long = 0,
var title: String = "",
var content: String = "") {
fun getDetails() = "Item02(id=$id, title=$title, content=$content)"
}
fun main(args: Array<String>) {
val items = arrayOf(
Item02(2001),
Item02(2002),
Item02(2003)
)
// 使用迴圈處理陣列裡面的所有Item02物件
for (item in items) {
// 顯示Item02物件資訊
println(item.getDetails())
}
// 顯示:
// Item02(id=2001, title=, content=)
// Item02(id=2002, title=, content=)
// Item02(id=2003, title=, content=)
println()
for (item in items) {
// 設定每一個元素Item02物件的title與content屬性
item.title = "Hi"
item.content = "Hello"
}
for (item in items) {
println(item.getDetails())
}
// 顯示:
// Item02(id=2001, title=Hi, content=Hello)
// Item02(id=2002, title=Hi, content=Hello)
// Item02(id=2003, title=Hi, content=Hello)
}
其它建構式
在宣告類別的時候,使用主要建構式與參數的預設值,就可以應付一般建立的需求。如果需要在建立物件的時候,執行一些額外工作,你也可以使用下面的語法,在類別加入其它建構式的宣告。其它建構式的宣告後面,一定要使用this(…)呼叫主要建構式:
constructor(參數名稱: 參數型態,...): this(...) {
// 建構式執行的工作
}
下面的範例程式示範其它建構式的宣告與使用:
/* net.macdidi5.kotlin.tutorial.ch11.Item03.kt */
package net.macdidi5.kotlin.tutorial.ch11
class Item03 (val id: Long,
var title: String,
var content: String) {
// 宣告次要建構式
// 使用this呼叫主要建構式
constructor(id: Long): this(id, "", "")
fun getDetails() = "Item03(id=$id, title=$title, content=$content)"
}
fun main(args: Array<String>) {
val item0301 = Item03(301, "Hello", "Hello Kotlin!")
println(item0301.getDetails())
// 顯示: Item03(id=301, title=Hello, content=Hello Kotlin!)
val item0302 = Item03(302)
println(item0302.getDetails())
// 顯示: Item03(id=302, title=, content=)
}
宣告屬性與自定存取函式
宣告類別的時候,可以在主要建構式同時宣告參數與類別需要的屬性。如果類別還需要其它額外的屬性,例如下面的範例程式:
/* net.macdidi5.kotlin.tutorial.ch11.Item04.kt */
package net.macdidi5.kotlin.tutorial.ch11
// 宣告包含id(編號)、title(標題)與content(內容)三個參數的建構式
// 因為宣告建構式參數沒有使用val或var,所以它們只是建構式的參數,並不是類別的屬性
class Item04(_id: Long,
_title: String,
_content: String) {
// 宣告類別的屬性,並設定為建構式的參數
val id = _id
var title = _title
var content = _content
fun getDetails() = "Item03(id=$id, title=$title, content=$content)"
}
fun main(args: Array<String>) {
val item04 = Item04(4, "Greeting", "Good morning")
println(item04.getDetails())
// 顯示: Item04(id=4, title=Greeting, content=Good morning)
}
一般的應用不必使用上面範例程式的作法,不論是在主要建構式同時宣告參數與類別需要的屬性,或是另外在類別宣告需要的屬性,Kotlin都會自動為屬性加入預設的setter與getter函式,使用物件屬性值的時候,會自動轉換為呼叫setter與getter函式:
class Item(var id: Int)
fun main(args: Array<String>) {
val item = Item(100)
// 呼叫setId函式設定屬性值
item.id = 101
// 呼叫getId函式取得屬性值
println(item.id)
}
如果需要在設定或讀取屬性值的時候,執行一些額外的工作,就必須在類別宣告屬性,使用set與get關鍵字,為屬性宣告自定的setter與getter函式:
/* net.macdidi5.kotlin.tutorial.ch11.Item05.kt */
package net.macdidi5.kotlin.tutorial.ch11
class Item05(val id: Long,
_title: String,
_content: String = "") {
var title = _title
// 宣告屬性的setter函式
set(value: String) {
if (value.isNotEmpty()) {
// 使用field關鍵字取代屬性名稱title
field = value
}
}
var content = _content
// 宣告屬性的getter函式
get() {
// 使用field關鍵字取代屬性名稱content
return if (field.isEmpty()) "Empty" else field
}
fun getDetails() = "Item05(id=$id, title=$title, content=$content)"
}
fun main(args: Array<String>) {
val item05 = Item05(5, "Nice day")
println(item05.getDetails())
// 顯示: Item05(id=5, title=Nice day, content=Empty)
item05.title = ""
println("title=${item05.title}")
// 顯示: title=Nice day
item05.content = ""
println("content=${item05.content}")
// 顯示: content=Empty
//
item05.content = "Nice day"
println("content=${item05.content}")
// 顯示: content=Nice day
}
下一步
認識類別與物件基本的概念與設計以後,接下來準備瞭解物件導向技術中的繼承。設計功能比較複雜一些的應用程式,使用繼承可以簡化程式的撰寫,許多框架的應用,例如Android App,也都需要瞭解繼承的實作與特性。
相關的檔案都可以在GitHub瀏覽與下載。
http://github.com/macdidi5/Kotlin-Tutorial
後續 >> Kotlin Tutorial(12)繼承與函式覆寫
|
windmax1
06/25
您好!想請教一下次要建構式的使用時機??可以麻煩老師舉個例子嗎??看範例還是不曉得何時會用到@@"