【kotlin从入门到深坑】之类和继承

简介

本篇博客主要是介绍Kotlin语法中的【类和继承】相关的知识,帮助各位更快的掌握Kotlin,如果有疏漏或者错误,请在留言中指正,谢谢。 系列汇总地址


声明类

Kotlin中使用关键词class 声明类和java中保持一致,代码如下:

class Demo{ //class + 类名
    
}

类的构成=class +类名+类头(可选)+类体(可选),如果没有类体,括号也可省略

class Demo //class + 类名

主构造函数

在Kotlin的类中可以有一个主构造函数和多个次构造函数。我们看看什么样的算主构造函数,例子如下:

class Demo(){

}

看了例子估计心里开始有疑惑了,这和上面的例子有什么不同??仔细一看还真有不同,多了"()",这就声明了一个无参的主构造函数,当然你也可以声明有参数的,如下

class Demo(name: String){

}

主构造函数只是类头的一部分,还有一个可选关键词--constructor,当主构造函数想声明为非public 类型的时候,需要使用该关键词其他时候可以省略,例如:

class Demo private constructor(name: String){

}

这种情况一般是在写单例的时候会用到。

构造函数都有了,我们可以愉快的做些初始化了,但是但是要注意,主构造函数内不能包含任何代码。 这个时候我们需要使用另一个关键词 init,使用init 代码块进行初始化代码即可,如下:

class Demo private constructor(name: String) {
    init {//init代码块
        println("测试输出")
    }
}

上面的代码中name 可以直接使用在 init代码块内和类体内声明的属性初始化中使用,只有这两种情况,代码如下

class Demo (name: String) {
    init {
        println("测试输出"+name) //在此处使用可以
    }
    var nameTest=name //此处给nameTest赋值可以,但不可以单独使用
}

当然我们可以让上面的name 有更多的用途怎么办呢?可以这样写:

class Demo(var name: String) { //此处加入 var关键词
    init {
        println("测试输出" + name)
    }

    var nameTest = name

    fun printTest() { //方法内也可使用了
        println(name)
    }
}

不仅可以使用var关键词,还可以使用val,具体的差别之前我们说过,再次不再赘述。
使用该关键词后,name就等同于是该类的成员变量,就等同于你直接声明在类中。
对于Kotlin来说还有个好用的地方,就是你声明的类中变量不需要写get/set方法,默认就会有,可以直接用。

次构造函数

Kotlin中类也可以声明前缀有 constructor 的次构造函数,如下:

class Demo { //有个默认的无参主构造函数
  constructor(){// 有个无参次构造函数

  }
}

如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数 用 this 关键字即可

下面根据主构造函数是否重写来分别讲解,先说未重写:

class A{
    
}

如何写它的次构造函数呢?

class A {
    init {
        println("--A主构造--")
    }

    constructor(name: String) { //此处屏蔽了 默认的主构造函数
        println("--A次构造--")

    }
}

上面的写法会导致Kotlin的默认无参主构造函数不可调用, 也就导致constructor(name: String):this() 失效,但我们上面说过必须要委托给主构造函数,这怎么办?其实Kotlin内部仍然会走默认的主构造函数,也就是说如果是默认主构造是可以省略不写的,有的时候是想写也没法写

得到上面的结论是源于一个测试,代码如下:

var a = A("name"); //此处已经无法调用无参的,也就是默认的主构造失效,内部使用this() 也是不可以的

后面的打印结果

--A主构造--   //仍然走了主构造函数,此时只有默认主构造函数
--A次构造--   //然后再走次构造

所以得到上面的结论,在此佐证。 后续用实际代码详解,此处挖坑

有的筒子可能就会想了,如果我们仍然想要一个无参数的构造函数怎么写?

class A {
    init {
        println("--A主构造--")
    }

    constructor(name: String) {
        println("--A次构造--")

    }
    
    constructor(){ //增加一个无参的次构造函数
        
    }
}

还有另一个方式,就是重写主构造函数,这两种方法都类似 java中自己重写一个无参的构造函数,现在就是区分了主、次构造函数的重写。还需强调的是主构造如果重写了,次构造不允许再重写。下面写个重写主构造函数的,后面细说:

class A() { //重写此处
    init {
        println("--A主构造--")
    }

    constructor(name: String) : this() {
        println("--A次构造--")

    }

//    constructor(){ //次构造不允许使用
//        
//    }
}

下面我们讲一下重写主构造函数的
如下:

class Demo() { //没参数的主构造函数
    constructor(name: String) : this() { //次构造函数委托给
    }
}

此处就和默认的不一样了,这个地方需要使用this(),因为你重写了主构造函数。如果不重写是可以不写this()

通过上方的各种对比和例子我们对类的构造函数有了大概的了解,我们为了方便理解在这里总结一波,还有不明白的多看看例子:

  • 类只有一个主构造函数,但可以有一个或多个次构造函数

  • 次构造函数需要委托给主构造函数,可以通过直接或者间接的方式

  • 在声明期间,以主构造函数为主,如果主构造函数重写了对应的构造方法,次构造函数不能用重复的出现对应的构造函数,上面有例子说明。

  • 在调用期间,以次构造函数为主,如果未重写主构造函数,默认会有一个无参的主构造函数,如果重写一个无参次构造函数,则可调用的只有次构造函数。

创建类的实例

要创建一个类的实例,我们就像普通函数一样调用构造函数:

val invoice = Invoice()
val customer = Customer("Joe Smith")
//注意 Kotlin 并没有 new 关键字。

继承

在 Kotlin 中所有类都有一个共同的超类 Any,这对于没有超类型声明的类是默认超类:

class Example // 从 Any 隐式继承

Any 不是 java.lang.Object;尤其是,它除了 equals()、hashCode()和toString()外没有任何成员。 更多细节请查阅Java互操作性部分。

要声明一个显式的超类型,我们把类型放到类头的冒号之后:

open class A(p: Int) //注意此处的 open 关键词

class B(p: Int) : Base(p) //使用" :"

对于继承的类来说,它仍需满足之前类中主次构造函数的规定,还需满足继承类委托给被继承类的主构造函数(保证对应类的init模块都能运行的关键),此处的被委托的主构造函数如果是无参构造函数,可以省略不写

下面我们分两种类型去分别讲解,首先是未修改默认的主构造函数的情况:
我们先看一下被继承类:

open class BB { //未重写默主构造

    constructor(name: String) {
        println(name + "---BB")
    }


    constructor() {
        println(".....---BB")

    }
}

继承类:

class testA : BB { //此处testA也没重写主构造
    constructor(name: String) : super(name) {//--    1)
        println("A---" + name)
    }

    constructor() {//--  2)
        println("A---" + "ss")
    }
}

位置1处的构造函数,因为未重写主构造,所以本类的委托完成,所以只需委托父类即可,即可满足上面说的要求。

位置2处的构造函数,因为未重写主构造,所以本类的委托完成,又因为默认是委托父类的无参主构造函数(系统默认的或者重写的都满足),所以满足上面说的要求。

我们做下改动,将B 改动如下:

open class BB() {//重写默认主构造

    constructor(name: String):this() { //手动委托主构造
        println(name + "---BB")
    }


//    constructor() { //根据主次函数关系,此处无法存在
//        println(".....---BB")
//
//    }
}

这时候我们的继承类如何写呢?

class testA : BB {
    constructor(name: String) : super(name) {
        println("A---" + name)
    }

    constructor() {
        println("A---" + "ss")
    }
}

可以看到代码是没变化的,也就是说,只要是被继承类的主构造函数,是无参的,无论是默认还是重写都可以省略不写,当然也可以写上

class testA : BB {
    constructor(name: String) : super(name) {//可以选择不同的父类的主构造函数进行委托
        println("A---" + name)
    }

    constructor():super() {//无参的委托
        println("A---" + "ss")
    }
}

下面我们将一下修改默认主构造函数的情况

class testB(name: String) : BB(name) { //此处testB重写了默认主构造,所以此处B一定需要用主构造函数(直接或间接的)
    init {
        println(name + "99ss...---B")
    }

    constructor(name: String, age: Int) : this(name) {
        println(name + "...---B")
    }
}

也可以这样写:

class testB(name: String) : BB() { //此处必须有"()"
    init {
        println(name + "99ss...---B")
    }

    constructor(name: String, age: Int) : this(name) {  //此处不能使用super了,不能重复委托父类,主构造函数已经委托过了
        println(name + "...---B")
    }
}

下面我们总结一波:

  • 如果继承的类重写了默认主构造函数,此时必须用基类的主构造函数初始化(直接或间接)

  • 如果继承的类没重写默认的主构造函数,此时可以使用super关键词初始化,我们也说过,未重写的的默认主构造函数,次构造函数都会委托给它,所以本类内也满足了委托条件,对于类外,也委托了被继承类的主构造方法,完成了两个类的条件


总结

至此已经学完了Kotlin的类和继承相关的知识,多回顾多思考,继续后续内容

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容