【Kotlin 初学者】枚举类-密封类-数据类-继承(下)

简介: 三、数据类3.1 创建数据类3.2 toString、equals和hashCode的个性化实现3.3 ==符号3.4 copy() 函数3.5 解构声明四、 继承(extend)4.1 Any 超类4.2 继承类4.3 函数重写4.4 属性重写4.5 类型检测(is)

三、数据类


       使用 data class 关键字创建一个只包含数据的类,这种类又称数据类。这个是Kotlin独有的,Java没有数据类。


       编译器会自动的从主构造函数中根据所有声明的属性提取以下函数:


  • 生成 equals() 函数与 hasCode() 函数


  • 生成 toString() 函数,由类名(参数1 = 值1,参数2 = 值2,….) 构成


  • 由所定义的属性自动生成component1()、component2()、…、componentN()函数,其对应于属性的声明顺序。


  • copy() 函数


数据类需要满足以下条件:


  • 主构造函数至少包含一个参数。


  • 所有的主构造函数的参数必须标识为val或者var。


  • 数据类不可以声明为abstract,open,sealed或者inner。


  • 数据类不能继承其他类 (但是可以实现接口)。


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


在没有结构体的时候,大括号{}可省略。


3.1 创建数据类


data class DaTang (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统中原王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
    println(DaTang("唐朝", 289))
}

微信图片_20220524204010.png


 如果不使用 data class 关键字修饰,而使用class关键字修饰,如下:


微信图片_20220524204950.png


3.2 toString、equals和hashCode的个性化实现


微信图片_20220524205013.png


3.3 ==符号


data class DaTang (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统中原王朝,共历二十一帝,享国-$age-年。"
}
class DaTang2 (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统中原王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
    println(DaTang("唐朝", 289))
    // "==“比较的是内容  equals(Any)。
    // 因未重写Any的equals函数,使用的是Any默认equals函数,所以比较的还是引用。
    // "===" 比较的是引用(类所占的内存区域)
    println(DaTang2("唐朝", 289) == DaTang2("唐朝", 289))
    //这里使用的是data class,数据类重写了equals,比较的是数据类里面的数据。
    println(DaTang("唐朝", 289) == DaTang("唐朝", 289))
}


微信图片_20220524205114.png


3.4 copy() 函数


copy() 函数应该是类似Java中的clone() 方法


data class DaTang (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统中原王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
    val datang = DaTang("唐朝", 289)
    println(datang)//DaTang(name=唐朝, age=289)
    //创建了了一个新的对象
    val diguo = datang.copy(age=500)
    println(diguo)//DaTang(name=唐朝, age=500)
}


微信图片_20220524205149.png


3.5 解构声明


       数据类:由所定义的属性自动生成component1()、component2()、…、componentN()函数,其对应于属性的声明顺序。


       普通类:使用 operator 关键字定义component1()、component2()、…、componentN()函数。


data class DataDaSong(var name:String ,var age:Int)
class DaSong(var name:String ,var age:Int){
    //解构语法:必须从component1开始
    operator fun component1() = name
    operator fun component2() = age
}
fun main() {
    //使用普通类需要自己写component1、component2...componentN
    var (name,age) = DaSong("北宋",167)
    println("$name,是中国历史上继五代十国之后的朝代,传九位皇帝,享国-$age-年")
    //使用数据类支持解构语法,自动生成operator fun component1
    var (dataname,dataage) = DataDaSong("北宋",167)
    println("数据类:$dataname,是中国历史上继五代十国之后的朝代,传九位皇帝,享国-$dataage-年")
}


微信图片_20220524205448.png


查看数据类反编译代码:


微信图片_20220524205507.png


四、 继承(extend)


       Kotlin 允许一个类继承自另一个类,Kotlin 中所有类都继承自 Any 类,Any 类是所有类的超类,对于没有超类型声明的类是默认超类


       Kotlin 类默认都是封闭的,要让某个类开放继承,必须使用 open 关键字修饰它。


注意:

在 Kotlin 中 Any 类是所有类的超类

在 Java 中 Object 类是所有类的超类


4.1 Any 超类


       Any 默认提供了三个函数:


public open class Any {
    public open operator fun equals(other: Any?): Boolean
    public open fun hashCode(): Int
    public open fun toString(): String
}


从这里发现 无论是类还是函数,都使用了 open 关键字修饰。


       同时发现,这里只是定义了函数,没有实现。为什么呢?因为Kotlin是跨平台语言,可以在Android、macOS、Windows、JavaScript上运行,为了支持跨平台更友好,在不同平台有不同实现,所以在这里并未展示。


4.2 继承类


/* 食物基类 */
open class Food{
    fun explain() = "Food explain"
}
class Apple :Food(){
}


不加 open 关键字修饰是不让继承滴,如下图:


微信图片_20220524205741.png


4.3 函数重写


       在基类中,使用 fun 声明函数时,此函数默认为 final 修饰,不能被子类重写。

       如果允许子类重写该函数,那么必须使用 open 关键字修饰它, 子类重写函数使用 override 关键字。


/* 食物基类 */
open class Food{
    //函数必须用 open 关键字修饰,子类才能覆盖
    open fun explain() = "Food explain"
}
/* 继承Food */
class Apple :Food(){
    //使用 override 关键字覆盖父类函数
    override fun explain() = "Apple explain "
}


在 Kotlin 中 override 是个关键字而不是注解。


使用


fun main() {
    //多态:父类类型的引用子类类型的对象
    val f: Food = Apple()
    println(f.explain())
}


微信图片_20220524205829.png


4.4 属性重写


/* 食物基类 */
open class Food {
    open val price = 100
    ...
}
/* 继承Food */
class Apple : Food() {
    override var price = 36
    ...
}
fun main() {
    //多态:父类类型的引用子类类型的对象
    val f: Food = Apple()
    println(f.explain())//Apple explain 36
}


微信图片_20220524205858.png


4.5 类型检测(is)


       Kotlin的 is运算符 可以用来检查某个对象的类型。


    println(f is Food)//true
    println(f is Apple)//true
    println(f is File)//false


智能类型转换(as)

       Kotlin的 as运算符 可以用对某个对象进行类型转换。


微信图片_20220524205937.png


智能安全转换操作符:as?


       as?安全地转换成一种类型。 如果无法进行转换,则返回null,而不是抛出ClassCastException异常。

       咱就在上面的实例基础上修改。


    var asTest :String? = ""
    //不安全的转换操作符 as
//    println(asTest as Int)//ClassCastException
    //安全的转换操作符 as?
    println(asTest as? Int)//null


微信图片_20220524210014.png



相关文章
|
2月前
|
缓存 API Android开发
Android经典实战之Kotlin Flow中的3个数据相关的操作符:debounce、buffer和conflate
本文介绍了Kotlin中`Flow`的`debounce`、`buffer`及`conflate`三个操作符。`debounce`过滤快速连续数据,仅保留指定时间内的最后一个;`buffer`引入缓存减轻背压;`conflate`仅保留最新数据。通过示例展示了如何在搜索输入和数据流处理中应用这些操作符以提高程序效率和用户体验。
40 6
|
2月前
|
Kotlin
Kotlin 面向对象编程 (OOP) 基础:类、对象与继承详解
面向对象编程(OOP)是一种编程范式,它通过创建包含数据和方法的对象来组织代码。相较于过程式编程,OOP 提供了更快更清晰的结构,有助于遵守 DRY(Don't Repeat Yourself)原则,使代码更易于维护和扩展。在 Kotlin 中,类和对象是 OOP 的核心。类作为对象的模板,定义了对象的行为和状态;对象则是类的具体实例。例如,`Car` 类可以定义汽车的品牌、型号等属性,以及如驾驶和刹车等功能。通过构造函数可以快速初始化对象的属性。此外,Kotlin 支持继承机制,子类可以从父类继承属性和方法,促进代码重用。
31 2
|
2月前
|
设计模式 安全 编译器
Kotlin 中的密封类:详解与应用
【8月更文挑战第31天】
66 0
|
2月前
|
设计模式 安全 数据库连接
|
2月前
|
存储 前端开发 编译器
深入理解Kotlin中的数据类及其应用
【8月更文挑战第31天】
15 0
|
22天前
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
45 1
|
2月前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
41 4
|
3月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
**Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**
107 5
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
|
3月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin中常见作用域函数
**Kotlin作用域函数概览**: `let`, `run`, `with`, `apply`, `also`. `let`安全调用并返回结果; `run`在上下文中执行代码并返回结果; `with`执行代码块,返回结果; `apply`配置对象后返回自身; `also`附加操作后返回自身
42 8
|
3月前
|
安全 Java Android开发
探索Android应用开发中的Kotlin语言
【7月更文挑战第19天】在移动应用开发的浩瀚宇宙中,Kotlin这颗新星以其简洁、安全与现代化的特性,正迅速在Android开发者之间获得青睐。从基本的语法结构到高级的编程技巧,本文将引导读者穿梭于Kotlin的世界,揭示其如何优化Android应用的开发流程并提升代码的可读性与维护性。我们将一起探究Kotlin的核心概念,包括它的数据类型、类和接口、可见性修饰符以及高阶函数等特性,并了解这些特性是如何在实际项目中得以应用的。无论你是刚入门的新手还是寻求进阶的开发者,这篇文章都将为你提供有价值的见解和实践指导。
下一篇
无影云桌面