kotlin继承

1.子类构造器委托调用父类构造器

子类继承父类,子类构造器一定要直接或者间接委托调用调用父类构造器。

(1)子类有声明主构造器时

首先,子类次构造器一定要直接或者间接委托调用子类的主构造器;

其次,子类主构造器一定要委托调用父类构造器,从而子类次构造器能够通过主构造器间接委托调用父类构造器。

/**
 * 父类
 */
open class Father {
    //父类有一个带有形参的构造器
    constructor(name: String?) {

    }
}

/**
 * 子类
 */
class Son(name: String?) : Father(name) {//子类继承于父类,同时子类主构造器委托调用父类构造器
    constructor() : this(null) {//子类次构造器委托调用子类主构造器,间接委托调用父类构造器

    }
    constructor(name: String, age: Int) : this() {//子类次构造器委托调用子类其他次构造器,间接委托调用子类主构造器,从而间接委托调用父类构造器

    }
}

(2)子类未声明主构造器(但是声明了次构造器)时

子类无主构造器时,次构造器不需要委托调用子类主构造器或者其他次构造器,但需要直接或间接委托调用父类构造器。

/**
 * 父类
 */
open class Father {
    //父类有一个带有形参的构造器
    constructor(name: String?) {

    }
    //父类无参的次构造器
    constructor() {
        println("无参构造器")
    }
}

/**
 * 子类
 */
class Son : Father {
    constructor(name: String?, age: Int) : super(name) {//子类次构造器直接委托调用父类构造器

    }

    constructor() : this(null, 0) {//子类次构造器委托调用其他次构造器,间接委托调用父类构造器

    }

    constructor(age: Int) {//子类次构造器未显式委托调用子类其他次构造器,也没显示委托调用父类构造器时,会默认委托调用父类无参的构造器

    }
}

(3)子类未显式声明任何构造器时

子类未显式声明任何构造器时,系统会为子类自动生成一个无参的主构造器,因此继承时需要委托调用父类构造器。

/**
 * 父类
 */
open class Father {
    //父类有一个带有形参的构造器
    constructor(name: String?) {

    }
}

/**
 * 子类
 */
class Son : Father(null)//声明时需为无参主构造器委托调用父类构造器

2.重写

(1)重写方法

重写方法遵循“两同、两小、一大”原则

  • 两同:方法名相同、形参列表相同。

    /**
     * 父类
     */
    open class Father {
        protected open fun method(a: String) {
            println("父类方法,传入参数:$a")
        }
    }
    
    /**
     * 子类
     */
    class Son : Father() {
        protected override fun method(a: String) {
            println("子类类方法,传入参数:$a")
        }
    }
    
  • 两小:返回值类型比父类返回值类型小或相等、抛出异常类型比父类小或相等。

    /**
     * 父类
     */
    open class Father {
        protected open fun method(a: String) : Any? {
            println("父类方法,传入参数:$a")
            return null
        }
    }
    
    /**
     * 子类
     */
    class Son : Father() {
        protected override fun method(a: String) : String?{
            println("子类类方法,传入参数:$a")
            return "返回值"
        }
    }
    
  • 一大:访问权限比父类大或相等

    /**
     * 父类
     */
    open class Father {
        protected open fun method(a: String) : Any? {
            println("父类方法,传入参数:$a")
            return null
        }
    }
    
    /**
     * 子类
     */
    class Son : Father() {
        public override fun method(a: String) : String?{
            println("子类类方法,传入参数:$a")
            return "返回值"
        }
    }
    

(2)重写属性

  • 重写的子类属性的类型必须与分类属性类型兼容(变量类型)

    /**
     * 父类
     */
    open class Father {
        open var a : Float = 1.1f
    }
    
    /**
     * 子类
     */
    class Son : Father() {
        override var a : Float = 2.2f
    }
    
  • 子类属性访问权限必须大于等于父类类型

    /**
     * 父类
     */
    open class Father {
        protected open var a : Float = 1.1f
    }
    
    /**
     * 子类
     */
    class Son : Father() {
        public override var a : Float = 2.2f
    }
    
  • 只读属性(val)可被重写成读写属性(var),读写属性(var)不能被重写成只读属性(val)

    /**
     * 父类
     */
    open class Father {
        protected open val a : Float = 1.1f
    }
    
    /**
     * 子类
     */
    class Son : Father() {
        public override var a : Float = 2.2f
    }
    

(3)强制重写

当子类同时继承多个超类(只能继承一个类,但可以实现多个接口)时,如果超类成员(属性/方法)名称一样时,子类需强制重写该成员。

子类想调用父类该成员,需通过super<父类名>.成员的方式调用。

/**
 * 父接口
 */
interface FatherInterfs {
    var a: Float
    fun method() {
        println("执行父接口里面该方法 a的值为:$a")//2.2
    }
}

/**
 * 父类
 */
open class Father {
    protected open val a: Float = 1.1f
    open fun method() {
        println("执行父类该方法 $a")//2.2
    }
}

/**
 * 子类
 */
class Son : Father(), FatherInterfs {
    override var a: Float = 2.2f
    override fun method() {
        super<FatherInterfs>.method()
        super<Father>.method()
        println("执行子类该方法 $a")//2.2
        println("父接口a的值为 ${super<Father>.a}")//1.1
    }
}
posted @ 2019-05-24 19:15  谢光伟  阅读(667)  评论(0编辑  收藏  举报