开发者社区> mogqp3unktbnq> 正文

【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



版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
18616 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
27761 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
12982 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
21951 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
15319 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
19993 0
201
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载