Kotlin之类的继承及属性和方法的重写

继承

第一点: 在kotlin中声明一个类, 它默认是Any这个类的子类, 就和java中一个类默认是Object这个类的子类一样, 看下面类的声明:

// 默认是Any的子类,  类似于java里所有的类都是Object的子类一样
class CDemo

我们来看一下Any类是怎么定义的


这里需要注意几点:

1.Any类声明的时候前面有个open,  注意kotlin中如果类前面不加open, 则该类默认是final的, 也就是不能被继承, 当尝试去继承的时候会有如下错误:

Error:(8, 15) Kotlin: This type is final, so it cannot be inherited from

例如:

// 默认是Any的子类,  类似于java里所有的类都是Object的子类一样
class CDemo : Any()

// 如果前面不加 open 关键字, 则默认的类是final的, 也就是不能被集成, 会提示如下错误
// Error:(8, 15) Kotlin: This type is final, so it cannot be inherited from
class Demo2 : CDemo() {

}

2.Any类默认实现了三个方法: equal, hashcode, toString


第二点: 在写子类的时候需要注意的是: 如果子类有主构造函数, 那么基类必须在主构造函数中立即初始化, 例如:

open class Animal

// 如果子类有主构造函数, 那么基类必须在主构造函数中立即初始化
// 继承 使用":" 表明继承自哪个类, 这里Animal要写() 的原因是父类没有显式的构造函数, 所以系统加了一个默认的空参的构造函数
// 而如果父类有构造函数那么子类必须实现父类的构造函数
open class Dog(type : String) : Animal() {

}

Dog继承自Animal, 但是由于Animal里有个默认的构造函数, 所以需要 写成 ": Animal()",  如果父类有带参数的主构造函数, 那么一旦子类也有主构造函数一样也需要去实现父类的主构造函数例如:

// 由于Dog有一个带参的主构造函数, 所以ErHa在继承的时候必须去实现这个构造函数
class Husky(type : String, name : String) : Dog(type) {

}


第三点: 如果子类没有主构造函数, 那么必须要在次构造函数中用 super 关键字初始化父类,或者调用另一个次构造函数。初始化父类时,可以调用父类的不同构造方法。例如:

// 如果子类有主构造函数, 那么基类必须在主构造函数中立即初始化
// 继承 使用":" 表明继承自哪个类, 这里Animal要写() 的原因是父类没有显式的构造函数, 所以系统加了一个默认的空参的构造函数
// 而如果父类有构造函数那么子类必须实现父类的构造函数
open class Dog(type : String) : Animal() {

}

// 由于Dog有一个带参的主构造函数, 所以ErHa在继承的时候必须去实现这个构造函数
class Husky(type : String, name : String) : Dog(type) {

}

class GoldenRetriever : Dog {
    // 如果子类没有主构造函数, 有次构造函数, 需要在次构造函数中用super关键字调用父类的构造方法
    constructor(type : String = "金毛" , name: String, age: Int) : super (type) {

    }
}

class Alaska : Dog {
    // 如果子类没有主构造函数, 有次构造函数, 需要在次构造函数中用super关键字调用父类的构造方法
    constructor(name : String, age : Int) : super(name) {

    }

    // 也可以在次构造函数中, 调用其他的次构造函数, 再由其调用父类的构造函数
    constructor(type: String = "阿拉斯基", name: String, age: Int) : this (name, age){

    }
}

重写

需要注意的是如果父类的方法没有open声明, 那么该方法是不允许被重写的, 重写方法的时候需要使用override关键字注明,  还有一点就是子类可以选择不重写父类的方法, 示例代码如下:

package com.wbing.kotlindemo.demo2


open class Dog {
    fun shout() {
        println("汪汪")
    }
    open fun show() {
        println("萌萌哒")
    }
}

class Husky : Dog() {
    // 由于父类的shout方法没有写open, 也就是默认是final的, 所以这里不能重写shout方法
    // Error:(15, 5) Kotlin: 'shout' in 'Dog' is final and cannot be overridden  不能重写shout因为默认是final的
   /* override fun shout() {
        println("玩明汪")
    }*/

    // 重写父类方法的时候要加上override关键字, show方法也可以选择不进行重写
    override fun show() {
        println("傻")
    }
}

fun main(args: Array<String>) {
    val husky =  Husky()
    husky.shout()
    husky.show()
}

再次需要注意的是, 如果一个类集成了多个类/接口, 并且父类/接口中有相同名字的方法需要重写的时候, 那么子类这时候必须重写该方法, 并且如果子类想区分开父类的方法的时候, 可以使用super关键字调用不同父类的方法, 示例代码如下:

package com.wbing.kotlindemo.demo2


open class Dog {
    fun shout() {
        println("汪汪")
    }
    open fun show() {
        println("萌萌哒")
    }
}

interface WatchDog {
    // interface里不用写open, 因为默认就是open的
    fun show() {
        println("看门电子狗")
    }
}

// 使用接口的时候不用写(), 是因为接口是没有构造函数的
class Husky : Dog(), WatchDog {
    // 由于父类的shout方法没有写open, 也就是默认是final的, 所以这里不能重写父类的方法
    // Error:(15, 5) Kotlin: 'shout' in 'Dog' is final and cannot be overridden  不能重写shout因为默认是final的
    /*override fun shout() {
        println("玩明汪")
    }*/

    // 重写父类方法的时候要加上override关键字
    override fun show() {
        // 当重写的方法在父类中有多个实现的时候, 如果继承的多个类中, 有相同的方法需要重写的时候, 则子类必须重写该方法, 并且, 为了区分, 可以使用super关键字来调用不同的父类中的方法
        super<WatchDog>.show()  // 看萌电子狗
        super<Dog>.show() // 萌萌哒
    }
}

fun main(args: Array<String>) {
    val husky =  Husky()
    husky.shout()   // 汪汪
    husky.show()
}

关键需要注意的地方, 注释写的比较明白


重写父类的变量:

父类变量的重写的时候有几个需要注意的地方, 被重写的变量也要有open的声明, 并且, 子类可以使用var类型的变量去重写父类val类型的变量, 但是不能使用val类型的变量去重写父类var类型的变量, 如果使用val类型的变量去重写父类的var类型的变量, 那么子类这个val类型的变量会多一个set方法, 而val类型的变量是不允许有set方法的

package com.wbing.kotlindemo

open class A {
    open val x: Int get() {
        return 0
    }

    open var y : String = "a"
}

class B : A() {
    override val x: Int = 1
}

class C : A() {
    override  var x : Int = 2
    // Error:(17, 14) Kotlin: Var-property public open val y: String defined in com.wbing.kotlindemo.C cannot be overridden by val-property public open var y: String defined in com.wbing.kotlindemo.A
    override val y : String = "b"
}


Kotlin中,我们可以通过自定义setter方法重写实体的set方法。通过重写setter方法,我们可以在设置属性值之前、之后添加自定义逻辑或进行其他操作。 以下是一个示例,演示如何在Kotlin重写实体的set方法: ```kotlin // 定义一个实体 class Person { var name: String = "" set(value) { // 在设置属性值之前的逻辑 println("设置属性之前") // 设置属性值 field = value // 在设置属性值后的逻辑 println("设置属性之后") } } ``` 在上面的示例中,我们定义了一个名为Person的实体。该有一个名为name的属性,其型为String。我们在属性的setter方法重写了默认的set行为。 在重写的setter方法中,我们首先添加了在设置属性值之前的逻辑,即打印"设置属性之前"。接下来,我们使用`field`关键字设置属性值,`field`表示属性本身。最后,我们添加了在设置属性值之后的逻辑,即打印"设置属性之后"。 通过这种方式,我们可以在设置属性值之前、之后执行自己的逻辑。例如,我们可以在设置属性值之前验证输入的值,或在设置属性值之后触发其他操作。 使用重写的setter方法的示例代码如下: ```kotlin fun main() { val person = Person() person.name = "Alice" } ``` 运行上述代码,输出的结果如下: ``` 设置属性之前 设置属性之后 ``` 上述示例演示了在Kotlin中如何重写实体的set方法。通过重写setter方法,我们可以在设置属性值时添加自定义逻辑,以满足特定的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值