Kotlin learning: Kotlin inheritance

Kotlin inheritance

All classes in Kotlin inherit the Any class, which is the superclass of all classes, and the default superclass for classes without a supertype declaration

class Example // 从 Any 隐式继承

Any provides three functions by default

equals()

hashCode()

toString()

Note: Any is not java.lang.Object.

If a class is to be inherited, it can be modified with the open keyword

open class Base(p: Int)           // 定义基类

class Derived(p: Int) : Base(p)

Constructor

Subclass has a main constructor

If the subclass has a main constructor, the base class must be initialized immediately in the main constructor

open class Person(var name : String, var age : Int){// 基类

}

class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {

}

// 测试
fun main(args: Array<String>) {
    val s =  Student("Runoob", 18, "S12346", 89)
    println("学生名: ${s.name}")
    println("年龄: ${s.age}")
    println("学生号: ${s.no}")
    println("成绩: ${s.score}")
}

Output result

学生名: Runoob
年龄: 18
学生号: S12346
成绩: 89

Subclass has no main constructor

If the subclass does not have a main constructor, you must initialize the base class with the super keyword in each secondary constructor, or proxy another constructor. When initializing the base class, you can call the different construction methods of the base class

class Student : Person {

    constructor(ctx: Context) : super(ctx) {
    } 

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
    }
}

Instance

/**用户基类**/
open class Person(name:String){
    /**次级构造函数**/
    constructor(name:String,age:Int):this(name){
        //初始化
        println("-------基类次级构造函数---------")
    }
}

/**子类继承 Person 类**/
class Student:Person{

    /**次级构造函数**/
    constructor(name:String,age:Int,no:String,score:Int):super(name,age){
        println("-------继承类次级构造函数---------")
        println("学生名: ${name}")
        println("年龄: ${age}")
        println("学生号: ${no}")
        println("成绩: ${score}")
    }
}

fun main(args: Array<String>) {
    var s =  Student("Runoob", 18, "S12345", 89)
}

Output result

-------基类次级构造函数---------
-------继承类次级构造函数---------
学生名: Runoob
年龄: 18
学生号: S12345
成绩: 89

Rewrite

In the base class, when using fun to declare a function, this function defaults to final modification and cannot be overridden by subclasses. If the subclass is allowed to override the function, then it is necessary to manually add open to modify it, and the subclass override method uses the override keyword

/**用户基类**/
open class Person{
    open fun study(){       // 允许子类重写
        println("我毕业了")
    }
}

/**子类继承 Person 类**/
class Student : Person() {

    override fun study(){    // 重写方法
        println("我在读大学")
    }
}

fun main(args: Array<String>) {
    val s =  Student()
    s.study();

}

The output result is

我在读大学

If there are multiple identical methods (inherited or implemented from other classes, such as A and B), you must override this method and use the super paradigm to selectively call the implementation of the parent class

open class A {
    open fun f () { print("A") }
    fun a() { print("a") }
}

interface B {
    fun f() { print("B") } //接口的成员变量默认是 open 的
    fun b() { print("b") }
}

class C() : A() , B{
    override fun f() {
        super<A>.f()//调用 A.f()
        super<B>.f()//调用 B.f()
    }
}

fun main(args: Array<String>) {
    val c =  C()
    c.f();

}

C inherits from a() or b(). Not only can C inherit functions from A or B, but C can inherit functions shared by A() and B(). At this time, the function has only one implementation in. In order to eliminate ambiguity, the function must call the implementation of the function in A() and B() and provide its own implementation

The output result is

AB

Attribute rewriting

Property rewriting uses the override keyword, the property must have a compatible type, and each declared property can be rewritten through the initializer or getter method

open class Foo {
    open val x: Int get { …… }
}

class Bar1 : Foo() {
    override val x: Int = ……
}

You can override a val attribute with a var attribute, but the reverse is not possible. Because the val attribute itself defines the getter method, rewriting to the var attribute will additionally declare a setter method in the derived class

You can use the override keyword in the main constructor as part of the attribute declaration

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}

supplement

  • When a subclass inherits a parent class, it cannot have a variable with the same name as the parent class, unless the variable in the parent class is private, or the variable in the parent class is open and the subclass is overridden with the override keyword
  • The subclass does not have to call the method of the same name that is shared by the parent class and the interface
  • Regarding the subclass cannot use val to rewrite the var in the parent class, my guess is: the subclass rewrites the properties of the parent class, which means that the getter and setter methods of the property must be rewritten, and the val in the subclass cannot have The setter method cannot "override" the setter method of the var in the parent class, which is equivalent to narrowing the scope of use of the corresponding property in the parent class. It is not allowed, just like we can't rewrite a public method in the parent class to a private method.
  • If a variable wants to be initialized when it is defined, the variable must have a backing field field. The default getter and setter methods of the variable have field fields defined, but if we override the getter method and setter of this variable Method, and the keyword filed does not appear in the getter method and setter method, the compiler will report an error, prompting Initializer is not allowed here because this property has no backing field, unless the filed keyword is explicitly written (even if it Do nothing, just put it there. I understand that once it appears is equivalent to "declared", it can be used, and when defining variables, initialization requires the field to be "declared")

 

Guess you like

Origin blog.csdn.net/PrisonJoker/article/details/113749363