文章目錄
- 數據類型
- 枚舉類型
- 匿名類和伴生對象
- 單例類
- 伴生對象
數據類型
聲明一個數據類非常簡單:
//在class前面添加data關鍵字表示為一個數據類
data class Student(var name: String, var age: Int)
數據類聲明后,編譯器會根據主構造函數中聲明的所有屬性自動為其生成以下函數:
.equals()
/.hashCode()
.toString()
.componentN()
按聲明順序自動生成用于解構的函數.copy()
用于對對象進行拷貝
舉個栗子:
data class Student(var name: String, var age: Int)fun main() {val student1 = Student("小明", 18)val student2 = Student("小明", 18)println(student1==student2)println(student1)val (name, age) = student1println("$name, $age")
}
為了確保生成代碼的一致性和有效性,數據類必須滿足以下要求:
- 主構造函數中至少有一個參數
- 主構造函數中的參數必須標記為
val
或var
- 數據類不能是抽象的,可繼承的,密封的或內部的
此外,數據類的成員屬性生成遵循以下規則:
- 如果數據類主體中,
.equals()
.hashCode()
或.toString()
等函數存在顯式(手動)實現,或者在父類中有final實現,則不會自動生成這些函數
data class Student(var name: String, var age: Int) {override fun toString(): String = "我是自定義的toString"
}fun main() {val student = Student("小明", 18)println(student)
}
如果父類具有open operator fun componentN()
函數并返回兼容類型,數據類會生成相應的函數,并覆蓋父類的函數,如果由于關鍵字導致無法重寫父類對應的函數會直接導致報錯
open class Person {//此函數必須是open的,否則無法被數據類繼承open operator fun component1() = "我想當太空人"
}//自動覆蓋父類的component1函數
data class Student(var name: String, var age: Int): Person() fun main() {val (name, age) = Student("小明", 18)println("$name, $age")
}
- 不允許為
.componentN()
和.copy()
函數提供顯式實現
注意,編譯器只會根據主構造函數中定義的屬性生成對應函數,如果我們不希望某些屬性被添加到自動生成的函數中,我們需要手動將其移出主構造函數:
data class Student(var name: String) {var age: Int = 0 //age屬性不會被處理
}fun main() {val student1 = Student("小明")val student2 = Student("小明")student1.age = 17student2.age = 18println(student1==student2)println(student1)
}
數據類自帶一個拷貝對象的函數,使用.copy()
函數復制對象
data class Student(var name: String, var age: Int)fun main() {val student = Student("小明", 18)val copyStudent = student.copy()println(student==copyStudent)println(student===copyStudent)
}
還允許修改一些屬性,而其余保持不變
data class Student(var name: String, var age: Int)fun main() {val student = Student("小明", 18)val copyStudent = student.copy(age = 17)println(copyStudent)
}
枚舉類型
如果我們想要存儲和表示自定義的多種狀態,可以使用枚舉類型
//在類前面添加enum表示枚舉類
enum class TrafficLight {RED, YELLOW, GREEN
}fun main() {val light: TrafficLight = TrafficLight.REDprintln(light)println(light.name) //name屬性是String類型println(light.ordinal)println(TrafficLight.RED.ordinal)println(TrafficLight.YELLOW.ordinal)println(TrafficLight.GREEN.ordinal)
}
枚舉也可以具有成員,但不能命名為name,因為name用來返回枚舉名稱了
enum class TrafficLight(var type: String) {//枚舉在定義時必須填寫參數,如果后面還要編寫函數之類的其他內容,需在末尾添加;RED("紅燈"), YELLOW("黃燈"), GREEN("綠燈");fun isGreen() = this == GREENfun test() = println("我是$type")
}fun main() {val light: TrafficLight = TrafficLight.REDprintln(light.type)println(light.isGreen())light.test()
}
枚舉類型可以用于 when 表達式進行判斷,因為它的狀態是有限的
enum class TrafficLight(var type: String) {//枚舉在定義時必須填寫參數,如果后面還要編寫函數之類的其他內容,需在末尾添加;RED("紅燈"), YELLOW("黃燈"), GREEN("綠燈");
}fun main() {val light: TrafficLight = TrafficLight.REDval result: String = when (light) {TrafficLight.RED -> "禁止通行"TrafficLight.YELLOW -> "減速通行/準備停下"TrafficLight.GREEN -> "正常通行"}println(result)
}
在枚舉類中也可以編寫抽象函數,但需要枚舉自行實現
enum class TrafficLight(var type: String) {RED("紅燈") {override fun test() = println("我是紅燈, 禁止通行")}, YELLOW("黃燈") {override fun test() = println("我是黃燈, 是讓你減速, 不是踩油門沖過去")}, GREEN("綠燈") {override fun test() = println("我是綠燈, 速速離去")};abstract fun test()
}fun main() {val light: TrafficLight = TrafficLight.REDlight.test()
}
如果枚舉實現了某個接口,既可以成員實現也可以統一實現
interface Message {fun test()
}enum class TrafficLight(var type: String): Message {RED("紅燈") {override fun test() = println("我是紅燈, 禁止通行")}, YELLOW("黃燈") {override fun test() = println("我是黃燈, 是讓你減速, 不是踩油門沖過去")}, GREEN("綠燈") {override fun test() = println("我是綠燈, 速速離去")};
}
enum class TrafficLight(var type: String): Message {RED("紅燈"), YELLOW("黃燈"), GREEN("綠燈");override fun test() = println("回家收衣服咯")
}
匿名類和伴生對象
fun main() {val obj = object { //使用object關鍵字聲明一個匿名類并創建對象val name = "張三"override fun toString() = "我是匿名類, name: $name"}println(obj)
}
匿名類雖然沒名字,也可以定義成員,不過不能定義任何構造函數
匿名類也可以作為某個類的子類定義,或是某個接口的實現
interface Person {fun chat()
}fun main() {val obj: Person = object: Person {override fun chat() = println("以心為鞘,以養利劍")}obj.chat()
}
open class Human(val name: String)fun main() {val obj: Human = object: Human("蕭炎") {override fun toString() = "我是$name"}println(obj)
}
單例類
object關鍵字除了用于聲明匿名類型,也可以用于聲明單例類(整個程序中只能存在一個對象)
object Singleton {private val name = "超人強"override fun toString(): String = "我叫$name"
}fun main() {val singleton = Singleton //不能通過構造函數創建對象,通過類名直接得到此單例類的對象println(singleton)
}
object Singleton {fun test() = println("原神,啟動!")
}fun main() {Singleton.test() //單例定義的函數使用類名直接就能調用
}
伴生對象
實際上就是將一個單例類寫到某個類內部
class Student(val name: String, val age: Int) {//使用companion關鍵字在內部編寫一個伴生對象,它同樣是單例的companion object Tools {//伴生對象定義的函數可以直接通過外部類名調用fun create(name: String, age: Int) = Student(name, age)}
}fun main() {Student.create("小明", 18)Student("小紅", 19) //使用構造方法
}
伴生對象在類加載的時候就自動創建好了