kotlin小悟-这个继承有点不一样

Posted 林克在思考

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kotlin小悟-这个继承有点不一样相关的知识,希望对你有一定的参考价值。

今天聊聊kotlin中关于构造函数的一个话题。

我们知道,在kotlin中构造函数分为主构造函数和从构造函数,关于详细的内容,可以点击下面的文章链接了解。
Kotlin系列之主构造方法和初始化语句块
Kotlin系列之从构造方法

前置知识

我们经常会写这样的代码:

//父类
open class Father




// 子类
class Son: Father()
    

注意到子类在继承父类时,Father 后面的 () 了吗,这里表示父类的主构造函数,而且这个 () 不能少,因为子类的代码完整的写法是下面这样的:

class Son public constructor(): Father()


public作为构造函数的权限修饰符这个自然不用多说,后面紧跟的 constructor() 表示 Son 这个类的主构造函数。
所以上面的代码连起来可以理解为子类 Son 的主构造函数需要调用父类 Father 的主构造函数。这样你就知道了Father后面的括号是不能少的。
其实Java里面也是这样的规则,只是Java里面不分主构造函数和次构造函数。

现象

下面我们看一个现象:

// 父类
open class Father



// 子类
class Son: Father
    constructor()

    

你会发现,这时候子类继承了 Father,但是Father后面的 () 没有了。
与此同时,Son类中多了一个次构造函数。也就是说,在继承自某个类时,有时候父类后面的 () 是不写的,而且写了会报错。

揭开谜底

如果你Java基础扎实,应该可以猜出几分原因,下面就来解释一下上面这种现象。
首先,我们明确一点,在kotlin中,在声明类的同时书写的构造函数,被我们称为主构造函数,写在类内部的构造函数被我们称为次构造函数。
就像最开始演示的那样,我们经常会把下面的代码简写:

// 完整形式
class Son public constructor(): Father()



// 简写形式
class Son: Father()
    

简写的形式,没有写出主构造函数的声明,所以kotlin就像Java一样,会在编译时帮我们补一个无参的主构造函数上去。
但是,一旦我们在类内部声明了一个无参的次构造函数,就像下面这样:

class Son: Father
    constructor()

    

这样kotlin就不会再为我们补无参的主构造函数上去了,这时候Son这个类,就没有了主构造函数。
在原来我们这么做之前,语义是子类的主构造函数,需要调用父类的主构造函数,所以我们需要在Father后面加上括号,
现在子类没有主构造函数了,自然就不需要在声明时调用父类的主构造函数了,Father后面就不需要写括号了,只需要写Father来表明这是一种继承关系即可。

这就引出了另一个问题,这样写,那是不是子类的次构造函数就没法调用父类的主构造函数了。在Java里面子类的构造函数时一定要调用父类的构造函数的。难道在kotlin中不一样吗?

我们可以通过命令反编译生成的Son.class文件一探究竟。先切换到Son.class所在目录,并使用如下命令进行反编译:

cd out/production/Sample/
javap -c Son

反编译结果如下:

Compiled from "Son.kt"
public final class Son extends Father 
  public Son();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method Father."<init>":()V
       4: return

你可以很清楚地看到,最终还是会在编译时帮我们补上调用父类构造函数的代码的。

写在最后

其实kotlin跟Java有很多相似的地方,理解了Java,kotlin可以看作是Java的高级语法糖,但万变不离其宗。

以上是关于kotlin小悟-这个继承有点不一样的主要内容,如果未能解决你的问题,请参考以下文章

kotlin小悟-安全调用符

kotlin小悟-安全调用符

在Kotlin中声明常量-在编译时调用函数

Kotlin学习之路:继承

Kotlin学习与实践 类接口

(继承)virtual与访问控制