前语

本文主要解说kotlin数据类(DataClass)和关闭类(SealedClasses),包括运用数据类,目标仿制,数据类成员的解构,运用关闭类,以及数据类和关闭类在Android开发中的运用。


Kotlin文章列表

Kotlin文章列表: 点击此处跳转检查


目录

Kotlin基础(七):数据类和封闭类


1.1 数据类(DataClass)

Kotlin供给了许多简练、安全和表达性强的语法特性。其间一个十分有用的特性是数据类(data class)。

数据类是 Kotlin 中用于表明纯数据的一种特别类。它们一般用于封装数据,并且供给了一些有用的功用,如主动生成的 equals()hashCode()toString() 办法,以及 copy() 办法。这些办法答应你轻松地比较、仿制和打印数据类的实例。

要声明一个数据类,你能够运用 data 关键字,后边紧跟着类的声明。以下是一个简略的数据类的比方:

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

在上面的比方中,Person 是一个数据类,它有两个特点 nameage。Kotlin 会主动为数据类生成以下办法:

  • equals(other: Any?):用于比较两个目标是否持平。
  • hashCode():用于生成目标的哈希码。
  • toString():用于将目标转换为字符串的表明方式。
  • copy():用于仿制目标。

你能够运用这些办法来进行目标的比较、仿制和打印操作。例如:

val person1 = Person("Alice", 25)
val person2 = Person("Alice", 25)
println(person1 == person2)  // 输出: true
val person3 = person1.copy(age = 30)
println(person3)  // 输出: Person(name=Alice, age=30)

除了主动生成的办法外,数据类还能够承继自其他类、实现接口,以及界说额定的特点和办法。

总结来说,Kotlin 的数据类供给了一种便利的方式来表明纯数据,并主动为你生成一些常用的办法,减少了编写样板代码的工作量。

1.1.1 运用数据类

在 Kotlin 中,运用数据类(data class)十分简略。你能够按照以下步骤运用数据类:

  1. 声明数据类:运用 data 关键字声明数据类,并界说它的特点。
data class Person(val name: String, val age: Int)
  1. 创立数据类的实例:运用结构函数来创立数据类的实例,并传入相应的特点值。
val person = Person("Alice", 25)
  1. 拜访数据类的特点:运用点表明法来拜访数据类的特点。
println(person.name)  // 输出: Alice
println(person.age)   // 输出: 25
  1. 比较数据类的实例:数据类主动生成了 equals() 办法,能够直接用于比较两个目标是否持平。
val person1 = Person("Alice", 25)
val person2 = Person("Alice", 25)
println(person1 == person2)  // 输出: true
  1. 仿制数据类的实例:数据类主动生成了 copy() 办法,能够用于创立数据类实例的副本,并能够挑选性地修正特点的值。
val person3 = person1.copy(age = 30)
println(person3)  // 输出: Person(name=Alice, age=30)
  1. 其他主动生成的办法:数据类还主动生成了 hashCode()toString() 办法。hashCode() 办法用于生成目标的哈希码,toString() 办法用于将目标转换为字符串的表明方式。
println(person.hashCode())  // 输出: 依据特点值生成的哈希码
println(person.toString())  // 输出: Person(name=Alice, age=25)

需求留意的是,数据类的主结构函数有必要至少有一个参数。假如你期望某个特点不参加比较、仿制或生成哈希码,能够将其声明为 valvar 之前加上 @Transient 注解。

data class Person(val name: String, @Transient val age: Int)

这样,age 特点将被疏忽,并不会影响生成的办法。

总之,Kotlin 的数据类供给了一种便利的方式来界说和运用纯数据,并主动为你生成一些常用的办法,简化了对数据的操作。

1.1.2 目标仿制

在 Kotlin 中,你能够运用数据类(data class)主动生成的 copy() 办法来仿制目标并创立其副本。这个办法答应你挑选性地修正副本的特点值。

以下是运用 copy() 办法进行目标仿制的示例:

data class Person(val name: String, val age: Int)
val person1 = Person("Alice", 25)
val person2 = person1.copy()
println(person1)  // 输出: Person(name=Alice, age=25)
println(person2)  // 输出: Person(name=Alice, age=25)
println(person1 === person2)  // 输出: false(两个目标不是同一个引证)

在上面的比方中,person1 是一个 Person 目标,经过调用 copy() 办法创立了 person2 的副本。copy() 办法会仿制一切特点的值,并回来一个新的目标。

你还能够挑选性地修正副本的特点值。能够经过在 copy() 办法中指定新的特点值来实现:

val person3 = person1.copy(age = 30)
println(person3)  // 输出: Person(name=Alice, age=30)

在上面的比方中,person3person1 的副本,可是修正了 age 特点的值。

需求留意的是,copy() 办法只仿制数据类的特点值,而不会仿制其他相关目标的引证。假如你的数据类包括其他目标类型的特点,它们将会被浅仿制,也便是仿制引证而不是实践目标。假如需求深仿制,需求手动处理相关目标的仿制逻辑。

总结来说,运用数据类主动生成的 copy() 办法能够轻松地仿制目标并创立副本。你能够挑选性地修正副本的特点值,而不影响原始目标。这是 Kotlin 中便利且灵敏的目标仿制机制。

1.1.3 数据类成员的解构

在 Kotlin 中,数据类(data class)的成员能够经过解构(destructuring)来拜访和运用。解构答应你将一个目标的特点拆解为多个独立的变量,以便更便利地运用这些特点。

要运用解构,你能够将一个数据类的实例赋值给多个变量。每个变量的称号与数据类的特点称号相对应。以下是一个运用解构的示例:

data class Person(val name: String, val age: Int)
val person = Person("Alice", 25)
val (name, age) = person
println(name)  // 输出: Alice
println(age)   // 输出: 25

在上面的比方中,咱们将 person 目标解构为两个变量 nameage。这样,咱们能够直接运用这两个变量来拜访目标的特点值。

解构不只限于单个数据类目标,还能够在集合中运用。例如,你能够解构一个包括多个数据类目标的列表:

val people = listOf(
    Person("Alice", 25),
    Person("Bob", 30),
    Person("Charlie", 35)
)
for ((name, age) in people) {
    println("Name: $name, Age: $age")
}

在上面的比方中,咱们运用解构在循环中拜访 people 列表中每个目标的特点。经过解构,咱们能够直接在循环体内运用 nameage 变量。

需求留意的是,解构只能用于拜访数据类的特点。假如你需求拜访其他办法或自界说的成员,依然需求经过目标称号来调用。

总结来说,Kotlin 中的解构答应你将数据类目标的特点拆解为多个独立的变量,以便更便利地运用这些特点。你能够在赋值语句或循环中运用解构来拜访数据类的成员。这是一种简练、便利的语言特性,能够进步代码的可读性和易用性

1.1.4 kotlin数据类在Android开发中的运用

在Android开发中,Kotlin数据类十分实用,特别是用于存储和传递数据目标,比方表明网络恳求的数据模型、Intent传递的数据目标、RecyclerView的数据项等。下面将分别举例说明Kotlin数据类在这些场景中的运用。

示例1:网络恳求数据模型

假定咱们有一个简略的用户数据模型,用于表明从服务器获取的用户信息,包括用户名和年纪。

data class User(val username: String, val age: Int)

示例2:Intent传递数据

当咱们需求在Activity之间传递数据时,Kotlin数据类能够协助咱们轻松地创立可序列化的目标,以便Intent传递数据。

在发送端Activity:

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
data class Person(val name: String, val age: Int)
class SenderActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sender)
        val person = Person("John Doe", 30)
        val intent = Intent(this, ReceiverActivity::class.java)
        intent.putExtra("PERSON_DATA", person)
        startActivity(intent)
    }
}

在接收端Activity:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
data class Person(val name: String, val age: Int)
class ReceiverActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_receiver)
        val person = intent.getSerializableExtra("PERSON_DATA") as? Person
        if (person != null) {
            // 运用接收到的Person目标进行操作
            // 例如:显现称号和年纪
        }
    }
}

示例3:RecyclerView的数据项

在RecyclerView中,咱们常常需求运用数据类来表明每个列表项的数据。

首要,在RecyclerView的适配器中界说一个数据类,用于表明列表项的数据:

data class Item(val title: String, val description: String)

然后,在适配器中运用这个数据类:

class ItemAdapter(private val itemList: List<Item>) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
    // ... 适配器的其他代码 ...
    override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
        val currentItem = itemList[position]
        holder.bind(currentItem)
    }
    inner class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(item: Item) {
            // 在ViewHolder中绑定数据到视图
            itemView.titleTextView.text = item.title
            itemView.descriptionTextView.text = item.description
        }
    }
}

这样,咱们就能够在RecyclerView中运用数据类Item来表明每个列表项的数据,并经过适配器将数据绑定到对应的视图上。

总结:
Kotlin数据类在Android开发中广泛用于数据目标的界说和传递。它们简练、类型安全且供给了主动生成的办法,极大地简化了Android开发中数据处理的代码。在网络恳求的数据模型、Intent传递数据以及RecyclerView的数据项等场景中,Kotlin数据类都能发挥重要的效果。

1.2 关闭类(SealedClasses)

1.2.1 运用关闭类

在 Kotlin 中,关闭类(sealed class)是一种特别的类,用于限制类的承继层级。关闭类的一切子类有必要在同一文件中界说,并且不能在类外部继续扩展。

关闭类用于表明一组相关的类或状况,并且一般与形式匹配(pattern matching)一同运用。它能够作为一个类的抽象基类,界说一些通用的行为和特点,然后由其子类实现具体的细节。

以下是一个关闭类的示例:

sealed class Result
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
object Loading : Result()

在上面的示例中,Result 是一个关闭类。它有三个子类:SuccessErrorLoadingSuccessError 是数据类,它们分别携带了一个特点 datamessageLoading 是一个单例目标。

关闭类的长处在于,当你运用 when 表达式(或者 if 表达式)进行形式匹配时,编译器会强制要求你处理一切或许的子类状况。这样能够保证代码的完整性,避免遗漏某些状况。

以下是一个运用关闭类的形式匹配的示例:

fun processResult(result: Result) {
    when (result) {
        is Success -> println("Success: ${result.data}")
        is Error -> println("Error: ${result.message}")
        Loading -> println("Loading...")
    }
}
val result1: Result = Success("Data loaded successfully")
val result2: Result = Error("Failed to load data")
val result3: Result = Loading
processResult(result1)  // 输出: Success: Data loaded successfully
processResult(result2)  // 输出: Error: Failed to load data
processResult(result3)  // 输出: Loading...

在上面的示例中,processResult() 函数接受一个 Result 目标,并运用 when 表达式依据不同的子类状况进行处理。

需求留意的是,关闭类的子类能够界说在关闭类内部,也能够界说在同一文件的顶层。这取决于你的需求和代码的安排结构。

总结来说,关闭类是 Kotlin 中用于限制类的承继层级的一种特别类。它一般与形式匹配一同运用,能够保证处理一切或许的子类状况,进步代码的安全性和可读性。

1.2.2 kotlin关闭类在Android开发中的运用

在Android开发中,Kotlin的关闭类(Sealed Class)能够用于表明特定状况、状况机或表达式的状况,并且限制这些状况的规模。关闭类十分适用于处理复杂的状况切换或表明一组有限的相关状况。

下面将分别举例说明Kotlin关闭类在Android开发中的两个运用场景:表明加载状况和表达式求值。

示例1:表明加载状况

假定咱们有一个简略的数据恳求的场景,咱们需求表明数据的三种状况:加载中、加载成功和加载失利。

首要,界说一个关闭类DataState来表明这些状况:

sealed class DataState {
    object Loading : DataState()
    data class Success(val data: String) : DataState()
    data class Error(val message: String) : DataState()
}

接下来,在某个ViewModel中运用这个关闭类来表明数据的不同状况:

class DataViewModel : ViewModel() {
    private val _dataState = MutableLiveData<DataState>()
    val dataState: LiveData<DataState>
        get() = _dataState
    fun fetchData() {
        // 模仿数据恳求,这里用延时来模仿网络恳求的进程
        _dataState.value = DataState.Loading
        // 假定在此处进行实践的数据恳求,并依据恳求成果更新_dataState的值
        // 假如恳求成功,则设置DataState.Success(data);假如恳求失利,则设置DataState.Error(message)
    }
}

接着,在Activity或Fragment中观察DataViewModel中的dataState,依据不同的状况进行相应的UI展现:

class DataActivity : AppCompatActivity() {
    private val dataViewModel: DataViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_data)
        dataViewModel.dataState.observe(this, { dataState ->
            when (dataState) {
                is DataState.Loading -> showLoadingView()
                is DataState.Success -> showData(dataState.data)
                is DataState.Error -> showError(dataState.message)
            }
        })
        fetchData()
    }
    private fun fetchData() {
        dataViewModel.fetchData()
    }
    private fun showLoadingView() {
        // 显现加载中的UI
    }
    private fun showData(data: String) {
        // 显现数据的UI,运用传递过来的data
    }
    private fun showError(message: String) {
        // 显现过错的UI,运用传递过来的过错音讯
    }
}

示例2:表达式求值

另一个运用场景是用关闭类来表明表达式的求值成果,例如简略的加法和减法表达式:

sealed class Expression {
    data class Add(val num1: Int, val num2: Int) : Expression()
    data class Subtract(val num1: Int, val num2: Int) : Expression()
}

然后,咱们能够界说一个函数来计算这些表达式:

fun evaluateExpression(expression: Expression): Int {
    return when (expression) {
        is Expression.Add -> expression.num1 + expression.num2
        is Expression.Subtract -> expression.num1 - expression.num2
    }
}

在运用时,能够创立不同的表达式实例,并传递给evaluateExpression函数来得到求值成果:

val addExpression = Expression.Add(5, 3)
val subtractExpression = Expression.Subtract(10, 2)
val addResult = evaluateExpression(addExpression) // 成果为 8
val subtractResult = evaluateExpression(subtractExpression) // 成果为 8

总结:
Kotlin关闭类在Android开发中的运用场景有许多,其间上述两个示例是其间的两个常见场景:表明加载状况和表达式求值。经过运用关闭类,咱们能够将相关状况或表达式会集在一个类中,并限制这些状况或表达式的规模,从而使代码更加明晰、易于保护。