Kotlin基础语法 十四 、数据类与密封类

数据类

平时的Android开发中,为了解析后台人员给我们提供的接口返回的Json字符串,我们会根据这个字符串去创建一个类或者实例对象,在这个类中,只包含了一些我们需要的数据,以及为了处理这些数据而所编写的方法。这样的类,在Kotlin中就被称为数据类。

数据类的声明:
使用data关键字声明数据类
声明格式
data class 类名(val/var param1 :数据类型,…){}

说明:

  1. )使用data关键字声明数据类,必须写在class关键字之前。
  2. )没有类体大括号{}可省略。
  3. 构造函数中要求至少存在一个参数,并且必须使用val或var修饰。
    参数的默认值可有可无。(若要实例一个无参数的数据类,则就要用到默认值)
  4. )数据类不能是抽象、开放、密封或者内部的
  5. 数据类有其约定俗成的规定,当然这只是为增加代码的阅读性。
    即,当构造函数中的参过多时,为了代码的阅读性,一个参数的定义占据一行。
  6. 数据类是可以实现接口的,如(序列化接口),同时也是可以继承其他类的,如继承自一个密封类。

示例:
// 定义一个名为Person的数据类

data class Preson(
    var name : String ,
    val sex : Int ,
    var age : Int ,
)

这等价于Java中的:

public class Person {
    
    

    private String name;
    private int sex;
    private int age;
    
    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getSex() {
    
    
        return sex;
    }

    public void setSex(int sex) {
    
    
        this.sex = sex;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }
    
}
  1. )当我们声明一个数据类时,编辑器自动为这个类做了一些事情,它会根据主构造函数中所定义的属性自动生成下列方法:
    生成equals()函数与hasCode()函数
    生成toString()函数,格式是:类名(参数1 = 值1,参数2 = 值2,…)构成
    由所定义的属性自动生成component1()、component2()、…、componentN()函数,其对应于属性的声明顺序。
    copy()函数。在很多情况下,我们需要复制一个对象改变它的一些属性,但其余部分保持不变。 copy() 函数就是为此而生成。
    val jack = Preson(“Jack”, 1,26)
    val olderJack = jack.copy(age = 56)

密封类

密封类用来表示受限的类继承结构:当一个值为有限几种的类型、而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。
要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明

声明格式
sealed class 类名()
示例:

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

说明:

  1. 一个密封类是自身抽象的,它不能直接实例化并可以有抽象(abstract)成员。即sealed class Expr 其实等于
    sealed abstract class Expr //编译器会提示:修饰符abstract是多余的因为 sealed已经存在
  2. 密封类不允许有非private 构造函数(其构造函数默认为 private)
    sealed class Expr public constructor() {} //编译器会报错,提示一个密封类不能有public的构造方法
  3. )使用密封类的关键好处在于使用 when 表达式 的时候,如果能够验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。当然,这只有当你用 when 作为表达式(使用结果)而不是作为语句时才有用。
fun eval(expr: Expr): Double = when(expr) {
    
    
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
    // 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}
  1. )如果 when 语句的分支不需要携带额外数据,可以用用 object 关键字创建单例,此时 when 子句不需要使用 is 关键字。如果需要携带额外信息我们才定义密封类的子类,而且使用了密封类就不需要使用 else 子句,因为每当我们多增加一个密封类的子类或单例,编译器就会在 when 语句中给出提示,可以在编译阶段就及时发现错误,这也是以往 switch-case 语句和枚举不具备的功能。
fun eval(expr : Expr) : Double =
        when (expr) {
    
    
            is Const -> expr.number
            is Sum -> eval(expr.e1) + eval(expr.e2)
            //编译器报错 ,提示 when 表达式必须是全面的,需要增加 NotANumber 或 else 分支。
        }
  1. )密封类 和枚举是很相似的,都使用于描述某种状态或情况的集合。
    区别在于:
    枚举类的每一个枚举常量都是枚举类的实例。所以不需要我们自己创建,但是这也限制了我们为枚举设置动态属性等操作
    而密封类是抽象的,密封类的子类可以任意扩展,这利于我们的灵活操作和后期扩展。密封类也友好的提供了when表达式的支持。

所以如果我们只需要标识一种状态而不需要动态的改变这种状态的信息,推荐使用枚举即可。如果我们需要对每种状态动态赋值、动态操作,推荐使用密封类

猜你喜欢

转载自blog.csdn.net/weixin_43864176/article/details/124132323