Kotlin基础九:class

104 阅读3分钟

前言

Kotlin中的类可以分为:数据类、密封类、枚举类 在开发中经常会用到。熟练掌握对我们以后开发是很重要的。

数据类

声明一个仅仅保存数据的类,用data关键字,放到class前面

data class Person(var name:String,var age:Int)

函数构造器中声明两个属性name和age。

  • 数据类的主构造函数至少有一个参数
  • 数据类主构造函数中的参数需要声明为varval
data calss Person(var name:String){
    var age:Int = 18
}

Kotlin编译器为数据类Person生成toString equals hashCode copy 都涉及到name属性,不会涉及到age属性。包括ComponentN函数。

解构声明

数据类的主构造函数声明一个属性,Kotlin编译器会自动生成一个ComponentN函数与之顺序对应。可以通过点击Decompile查看反编译Java代码。 将Person对象接构成变量name和age

fun test() {
    val (name,age) = Person("xiake",18)
}
data class Person(var name:String,var age:Int)

map遍历

fun test() {
    val map = mapOf(0 to "A",1 to "B")
    for ((key,value) in map){
        println("key:$key value:$value")
    }
}
输出:
key:0 value:A
key:1 value:B

使用解构声明将类型为Map.Entry<Int,String>对象解析成key value变量。可以在Lambda中使用解构声明。

fun test() {
    normal { (name,age)-> println("name:$name age:$age") }
}
data class Person(var name:String,var age:Int)
private fun normal(block:(Person)->Unit){
    block.invoke(Person("xiake",18))
}

函数有多个参数时,用逗号将解构和参数分开

fun test() {
    normal { (name,age),from-> println("name:$name age:$age") }
}
data class Person(var name:String,var age:Int)
private fun normal(block:(Person,String)->Unit){
    block.invoke(Person("xiake",18),"normal")
}

List集合可以使用解构声明,默认最多支持前5个元素

fun test() {
    normal { (name,age),from-> println("name:$name age:$age") }
    val (a,b,c,d,e) = listOf("A","B","C","E","F","G")
}

自kotlin1.1后,在解构声明中不需要某个变量,可以像Lambda参数一样,用下划线代替名称

val (name,_) = Person("xiake",18)

Kotlin编译器不会再调用相应的ComponentN函数

copy函数

在已有对象基础上稍作修改获取另一个新对象

fun test() {
    val person = Person("xiake",18)
    val nPerson = person.copy(name = "xiake2")
}
data class Person(var name:String,var age:Int)

copy函数实现类似如下

fun copy(name:String = this.name,age:Int = this.age) = Person(name,age)

Pair和Triple

kotlin内置数据类型。Pair类有两个属性参数,用中缀函数to创建Pair对象

val point = 10 to 100

用Pair扩展函数toList,将Pair对象转成List对象

val list = point.toList()

Triple声明了三个属性参数的数据类,提供了toList扩展函数

Triple(1,2,3).toList()

Tuples.kt源码

public data class Pair<out A, out B>(
    public val first: A,
    public val second: B
) : Serializable {
    public override fun toString(): String = "($first, $second)"
}
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
public fun <T> Pair<T, T>.toList(): List<T> = listOf(first, second)
public data class Triple<out A, out B, out C>(
    public val first: A,
    public val second: B,
    public val third: C
) : Serializable {
    public override fun toString(): String = "($first, $second, $third)"
}
public fun <T> Triple<T, T, T>.toList(): List<T> = listOf(first, second, third)

密封类

在kotlin中密封类使用sealed,放到calss之前

sealed class CrType
class Car: CarTpe()
calss SUV: CarType()
class BUS: CarType()

用来表示受限的类继承结构:一个值为有限的几种类型 不能有任何其他类型。像枚举类型的扩展:枚举类型的值集合也是受限的,每个枚举常量只存在一个实例 密封类的一个子类可以包含状态多个实例。使用密封类好处,当使用when表达式,只要覆盖到该密封类的所有子类型,无需编写else

fun test() {
    println(getCarName(Car()))
}
sealed class CarType
class Car :CarType()
class SUV :CarType()
class BUS :CarType()
fun getCarName(carType:CarType):String{
    return when(carType){
        is Car ->"Car"
        is SUV ->"SUV"
        is BUS ->"bus"
    }
}

密封类本身是抽象的,没办法直接创建一个密封类对象,可以定义抽象方法或属性

sealed class CarType{
    abstract val name:String
    abstract fun info():String
}

枚举类

声明一个枚举类型关键字enum

enum class LoadState{
    Success,
    Failure
}

每个枚举类只存在一个实例。拥有一个name属性和一个ordlinal属性。name表示枚举类常量的名字,ordinal表示常量声明的顺序。用枚举的values()方法获取所有常量数组。

fun test() {
    for (state in LoadState.values()){
        println("name:${state.name} index:${state.ordinal}")
    }
}
enum class LoadState{
    Success,
    Failure
}
输出:
name:Success index:0
name:Failure index:1

valuesof(String)方法通过指定名称获取具体的枚举常量,若通过名称未获取指定名称则抛出异常IllegalArgumentException:

fun test() {
    println(LoadState.valueOf("hello"))
}
enum class LoadState{
    Success,
    Failure
}
异常:
No enum constant com.georege.leetcode2.ExampleUnitTest.LoadState.hello
java.lang.IllegalArgumentException: No enum constant com.georege.leetcode2.ExampleUnitTest.LoadState.hello
	at java.base/java.lang.Enum.valueOf(Enum.java:273)
	at com.georege.leetcode2.ExampleUnitTest$LoadState.valueOf(Test.kt)
	at com.georege.leetcode2.ExampleUnitTest.test(Test.kt:14)

传入正确的枚举常量名称:

fun test() {
    println(LoadState.valueOf(LoadState.Success.name))
}
enum class LoadState{
    Success,
    Failure
}
输出:
Success

在主构造函数给枚举类新增属性:

fun test() {
    for (color in Color.values()){
        println(color.rgb)
    }
}
enum class Color(val rgb:Int){
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}
输出:
16711680
65280
255

和密封类一样,枚举本身是抽象类,可以添加抽象属性和方法:

fun test() {
    for (state in LoadState.values()){
        println(state.state)
    }
}
enum class LoadState{
    Success{
        override val state = true
    },Failure{
        override val state = false
    };
    abstract val state:Boolean
}
输出:
true
false

在给枚举类添加抽象属性或方法,需要在声明最后一个枚举类使用分号;隔开。Kotlin1.1起,可使用enumValues<T>enumValueOf<T>函数以泛型方式访问枚举类中的常量

fun test() {
    printAll<LoadState>()
    println(LoadState.Success)
}
enum class LoadState {
    Success {
        override val state = true
    },
    Failure {
        override val state = false
    };
    abstract val state:Boolean
}
inline fun <reified T:Enum<T>> printAll(){
    enumValues<T>().onEach { println(it.name) }
}
inline fun <reified R:Enum<R>> R.getEnum():Enum<R>{
    return enumValueOf<R>(this.name)
}
输出:
Success
Failure
Success

总结

数据类、密封类、枚举类在Kotlin中经常用到,熟练掌握相关基础知识,对Kotlin开发是很重要的。