带你踏入kotlin大门(五)|基本功_类和继承篇


带你踏入kotlin大门(五)|基本功_类和继承篇

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

带你踏入Kotlin大门(一)|kotlin初识 - 掘金 (juejin.cn)

带你踏入kotlin大门(二)|基本功_变量篇 - 掘金 (juejin.cn)

带你踏入kotlin大门(三)|基本功_函数篇 - 掘金 (juejin.cn)

带你踏入kotlin大门(四)|基本功_逻辑控制篇 - 掘金 (juejin.cn)

带你踏入kotlin大门(五)|基本功_类和继承篇 - 掘金 (juejin.cn)

带你踏入Kotlin大门(六)|基本功_接口和特殊类篇 - 掘金 (juejin.cn)

前置知识

  • 已学习 Kotlin 变量、函数知识
  • Java 编程基础

前言

本篇作为 Kotlin 基本功的倒数第二篇,将为大家带来关于 Kotlin 中类和继承的知识。如果你看到这篇文章的时候,还未听说过 Kotlin 或者从未学习过 Kotlin ,你可以点击链接从本系列的第一篇文章开始学习。在本系列前面的文章中,我们学习到了关于 Kotlin 的函数、变量还有逻辑控制的知识;而当你学完本篇后,你掌握了 Kotlin 中类和继承的知识,你就是学会了 Kotlin 中大部分的知识了。

话不多说,赶紧学起来吧!

Kotlin的OOP VS Java的OOP

OOP 就是面向对象的缩写。在 Java 中,其三大特性分别是 封装、继承和多态。如果不太记得三大特性是什么了,可以查看我的另一个专栏——设计模式专栏的文章,里面有简单的总结了三大特性。那么在 Kotlin 中的面向对象和 java 的面向对象有什么区别呢?我在这里言简意赅的回答你,特性和理论是一样的,但使用方法不一样。那么,使用方法上有何不同呢?下面听我细细道来,我们简单的创建一个类和继承对应的类,用这个实战的过程带你学明白 Kotlin 的类。

ps:封装在前文已做讲解。

Kotlin 类和普通创建

要了解一个东西,我们需先窥其全貌。所以,我们可先看一下在 Kotlin 中类是长什么样子的。

从上述的截图中,我们可以看到,Kotlin 的类可以直接以 class 来声明,这点和 java 是一致的。但是上述的代码也有很多不一样的地方,譬如类后面和函数一样带有括号,且还有冒号用于继承等等这些我们 Java 开发者看来十分陌生的东西。

但我们对此不必害怕,我们学习完本文之后再来重新阅读就会一目了然了。

创建一个类

我们尝试自己创建一个 Kotlin 的类。创建步骤和创建 Java 类一样,只是最后选择 Koltin 文件即可。下面我们立刻来实战一下,从实战中学习。

第一步,我们定义一个空的类 ViewTest 。可以是如下这样子的。

class ViewTest{
	
}

第二部,我们向类里面添加属性和方法。最后去主函数中初始化这个类和调用其中的函数,这样子就是简单的创建和使用一个类了。这和 Java 没太大不同的。

class ViewTest{
    val string1 = "s1"
    val string2 = "s2"
    fun print(){
        println(string1 + string2)
    }
}

fun main() {
	val v = ViewTest()
    v.print()
    
}

但是上面的代码中,类的初始化和 Java 中有些不一样,你会发现这里无需在初始化的时候加 new 关键字,而其他都是一样的。下面附上代码的运行结果。

Kotlin 中的继承

下面我们继续学习它的继承特性。

Java 中,默认所有类都是可以被继承的,但是 Kotlin 中不一样,Kotlin 的设计遵循 多用组合少用继承 的思想,默认类不可被继承

如果类需要被继承,那么我们就需要在 class 前加一个 open 关键字。例如,我们想要使得上面的 ViewTest 类可以被继承,那么我们需要做如下修改。

open class ViewTest{
    val string1 = "s1"
    val string2 = "s2"
    fun print(){
        println(string1 + string2)
    }
}

这样子, ViewTest 类就可以被继承了。说明一下,Kotlin 中继承使用的关键字是。其次,我们创建一个子类继承这个 ViewTest 父类。然后运行这段代码。

你会惊奇的发现,程序运行出错啦!这是怎么回事呢?

上述的代码出现了一行红色的错误信息,这句错误信息翻译过来是:此类型具有构造函数,因此必须在此处初始化。

这时候,我们会懵圈了,构造函数?默认构造函数不是为空的吗?此处没有新添加构造函数,那么就默认调用父类空的构造函数才对呀!

确实,在 Java 中我们的确可以这样子理解,但是在 Kotlin 中,却并非如此。Kotlin 中的构造函数和 Java 的有很大的不同。

接下来我们继续学习 Kotlin 的构造函数,顺便解决这个bug。

构造函数

Kotlin 中,构造函数分为 主构造函数次构造函数,而一般情况下我们只需要使用到 主构造函数

主构造函数

Kotlin 的主构造函数也默认的是一个无参的函数,所以在首次执行 val v = ViewTest() 的时候是成功可行的。

而在 Kotlin 中,子类继承父类的时候,和 Java 一样是需要调用父类的构造函数的,但是 Kotlin 不会帮助你调用默认的主构造函数,如果你需要使用主构造函数,就需要手动的去声明继承父类的构造函数。

在上面子类的代码中,我们只是使用冒号:继承了 ViewTest() 这个类,却并未声明我们的类需要初始化父类的主构造函数是怎么样的。至于为何一定要声明,那是因为父类的主构造器参数可以是多样性的,不做声明就无法确定调用的父类主构造函数是怎么样的,不知道它有几个参数。所以我们直接在 ViewTest 后加上(),声明我们调用的父类的构造器是默认的,未改造的,就不会出错了。

class ViewSon : ViewTest(){
    
}

通过上面的结果图,我们可知这个bug解决了。

那么,主构造器可以如何多样化呢,这时候,我们就对其父类()内的参数进行扩增,就可以实现其多样化了。

将参数放到括号内,就是实现了构造函数属性初始化。

open class ViewTest(val string1: String, val string2: String){
    fun print(){
        println(string1 + string2)
    }
}

然后,我们继续使用子类继承它。下方代码中,只有独属于本类的,才可以用 valvar 关键字来修饰,属于父类的不做修饰。而声明父类的主构造器的时候,直接传入参数名即可。

class ViewSon(val s0: String, s1: String, s2: String) : ViewTest(s1,s2){
    
}

最后,我们来运行一下查看结果。

主构造函数就学到这里了。下面我们继续看次构造器。

次构造器

次构造器可以对主构造器做一个拓展,就像 Java 中,我们有多个构造器那样子。

此处直接上代码。

class ViewSon(val s0: String, s1: String, s2: String) : ViewTest(s1,s2){
    constructor(s1: String, s2: String): this("S0",s1,s2){
        
    }
    constructor(s1: String): this(s1,"s2"){
        
    }
    constructor(): this("s1")
}

上面代码中的次构造器,使用的是 constructor 关键字+ this 关键字来层层调用来实现多个构造函数。我们可以运行一下查看效果。

有一个知识点需要说明,那就是 只有次构造器的情况是存在的,但不常见,我们也可以使用这个特点来解决前文的bug。用子类的次构造器声明使用父类哪个构造器。在这种情况下,我们就需要使用 super 关键字来解决声明父类构造器了。

class ViewSon : ViewTest{
    constructor():super()
}

今天学习的就到这里了,加油!

参考

Kotlin Playground: Edit, Run, Share Kotlin Code Online (kotlinlang.org)


文章作者: DYJ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 DYJ !
评论
  目录