Kotlin Learning Road (6): Inheritance

foreword

Kotlin's inheritance is the same as Java's inheritance, the difference is that Kotlin :is used to replaceextends

1. Class inheritance

Kotlin uses it :to represent inheritance, and Java uses it extedsto represent inheritance.

// 父类Person
open class Person()

// 子类Man
class Man() : Person()

Above is the simplest Kotlin inheritance example. It should also be noted here that classes in Kotlin are final by default (meaning that the class is not allowed to be inherited), and it needs to be added classbefore the keyword opento indicate that the class can be inherited by other classes. Like Java, Kotlin also has single inheritance.
Like Java inheritance, subclasses can use the properties and methods of the parent class:

open class Person {
    
    
    var name: String = ""

    var age: Int = -1

    fun eat(){
    
    
        println("eat food!")
    }
}

class Man() : Person()

fun main() {
    
    
    val man = Man()
    man.age = 22
    man.name = "Tom"
    println("age is ${
      
      man.age}")
    println("name is ${
      
      man.name}")
    man.eat()
}

Output result:

age is 22
name is Tom
eat food!

As can be seen from the above code, subclasses Mancan use Personthe properties and methods of the parent class.

2. Constructor in inheritance

In the case of inheritance in Kotlin, what is the syntax of the constructor? Let's first look at how Java handles it.

2.1 Java constructor in inheritance

Java implements superaccess and passing values ​​to parent class constructors, similar to the following code:

// Person类(父类)
public class Person {
    
    
    private String name;

    private int age;

    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }
}

// Man类(子类)
public class Man extends Person{
    
    

    public Man(String name, int age) {
    
    
        super(name, age);
    }
}

superParameters can be passed to the parent class through keywords , and Create constructor matching superthe constructor can be automatically generated by clicking in AndroidStudio. Let's see how Kotlin handles this problem.

2.2 Kotlin constructor in inheritance

Implementing this function in Kotlin requires only a very small amount of code:

// Person
open class Person(var name:String, var age:Int) {
    
    
    // Empty Code
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    
	// Empty Code
}

fun main() {
    
    
    val man = Man("Tom", 22)
    println("name is ${
      
      man.name} age is ${
      
      man.age}")
}

Print result:

name is Tom age is 22

The parameters are passed through the constructor of the Man class , nameand agethen : Person(name, age)passed to the parent class.
Some people may ask, is it : Person(name, age)feasible without adding the latter?
Obviously not, Manthere is no class constructor var, then they are just Manparameters of the class constructor, not member variables of the class.
So if Manthe class is added, varis it possible?
The answer is no, so the parent class and the subclass will have two sets of member variables, and an error will definitely be reported. However, we can override the member variables of the parent class, which will be discussed in detail later.

2.3 The case of multiple constructors in Kotlin

Kotlin has primary and secondary constructors. If a parent class has multiple constructors, how does the subclass inherit it?
The first way of writing:

// Person类,这里有三个构造函数
open class Person(var name: String, var age: Int) {
    
    
    constructor(name: String): this(name, -1)
    constructor(age: Int): this("", age)
}

// Man类
class Man(name: String, age: Int) : Person(name, age) {
    
    
	// Empty Code
}

When the parent class has multiple constructors, it can be written in the same way as above. However, this prevents an object from being created as a secondary constructor.

fun main(){
    
    
    val man = Man("Tom") // 报错!
    println("name is ${
      
      man.name} age is ${
      
      man.age}")
}

The reason for this is that we only rewrite the primary constructor of the parent class, but not the secondary constructor of the parent class. For this situation, we can write like this. The same is the above example, the code is as follows:

// Person类,这里有三个构造函数
open class Person(var name: String, var age: Int) {
    
    
    constructor(name: String): this(name, -1) // 次构造函数
    constructor(age: Int): this("", age) // 次构造函数
}

// Man类
class Man: Person {
    
    
    constructor(name: String, age: Int) : super(name, age) // 对应Person类的主构造函数
    constructor(name: String) : super(name) // 对应Person类的constructor(name: String)
    constructor(age: Int) : super(age) // 对应Person类的constructor(age: Int)
}

Just rewrite the three sub-constructors of the parent class directly, and superjust use the constructor pointing to the parent class.
In order to facilitate and fast construction, you can use the shortcut creation method of AndroidStudio:
First, click the right mouse button inside the class, and the following menu will pop up: Click the Generate
Constructor shortcut creation
button in the pop-up menu , and then the following menu will pop up:
Constructor shortcut creation

Finally, click the Secondary Constructor button and select the constructor you need to rewrite:
Constructor shortcut creation
through this shortcut, you can quickly rewrite all the primary and secondary constructors of the parent class.

3. Rewriting and overloading

This chapter focuses on rewriting. As for overloading, you can read my previous article Kotlin Learning Road (3):
1.3 Summary in Functions

3.1 Method rewriting

The code is still the above example, but there is one more test method in the parent class:

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

    open fun testMethod(){
    
     // 注意这里加上了open,表示可以被重写。默认情况下是fina
        println("父类test!")
    }
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    

    override fun testMethod(){
    
     // 类似Java的override重写标志
        println("子类test!")
    }
}

fun main(){
    
    
    val man = Man("Tom", 22)
    man.testMethod()
}

Output result:

子类test!

What needs to be emphasized here is that Kotlin's methods are always the same before adding modifiers public final , especially , so add modifiers final to the methods that need to be overridden . The rewriting method needs to follow the principle of two same, two small, and one big .open

  • Two same: same method name, same parameter type
// Person
open class Person(var name:String, var age:Int) {
    
    

    open fun testMethod(str: String){
    
    
        println("父类test! $str")
    }
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    

    override fun testMethod(str: String){
    
    
        println("子类test! $str")
    }
}

fun main(){
    
    
    val man = Man("Tom", 22)
    man.testMethod("aaa")
}
  • Two small: the return value type of the subclass is smaller or equal to the return value type (return value type range) of the parent class, and the exception type thrown by the subclass is smaller or equal to that of the parent class
// Person
open class Person(var name:String, var age:Int) {
    
    

    open fun testMethod(): Any?{
    
    
        println("父类test!")
        return null
    }
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    

    override fun testMethod(): String{
    
    
        println("子类test!")
        return "test"
    }
}

In the above example, the return value type of the method of the parent class is Any?, and the return value type of the method of the subclass is String. From the perspective of inheritance relationship, the scope of Stringinheritance Any?is naturally Any?greater than String. However, this is generally not used much.

  • One big: the modifier permissions of the subclass are greater than or equal to the modifier permissions of the parent class
// Person
open class Person(var name:String, var age:Int) {
    
    

    protected open fun testMethod(): Any?{
    
    
        println("父类test!")
        return null
    }
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    

    override fun testMethod(): String {
    
    // 如果这里改为private就会报错
        println("子类test!")
        return "test"
    }
}

3.2 Rewriting of attributes

Property rewriting is similar to method rewriting:

// Person
open class Person(var name:String, var age:Int) {
    
    
    open var test = -1 // 和方法一样,加上了open
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    
    override var test = 0 // 这里加上了override标志
}

fun main(){
    
    
    val man = Man("Tom", 22)
    println("test value is ${
      
      man.test}")
}

Output result:

test value is 0

From the results, it can be seen that the member variables of the parent class testare overwritten by the subclass. In general, this function is rarely used, and rewriting attributes may break the Liskov substitution principle (subclasses can extend the functions of the parent class, but cannot change the original functions of the parent class)

4. super keyword

Kotlin, like Java, also has the super keyword. The usage is similar to Java, both refer to the parent class, and the usage is similar to Java.

4.1 Simple usage

// Person
open class Person(var name:String, var age:Int) {
    
    
    // Empty Code
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    

    fun test(){
    
    
        println("name is ${
      
      super.name}")
    }
}

fun main(){
    
    
    val man = Man("Tom", 22)
    man.test()
}

Output result:

name is Tom

The above example is more or less like taking off your pants and farting, but it can actually be removed super, here is just for demonstration. Its main function is still used for method rewriting.

4.2 Usage in complex situations

superHere is the usage in relatively complex situations .

4.2.1 Using super in the subclass override method

The method used in the rewriting method superis basically the same as Java:

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

    open var test = -1

    open fun testMethod(){
    
    
        println("父类test!")
    }
}

// Man类
class Man(name: String, age: Int): Person(name, age) {
    
    

    override var test = 0

    override fun testMethod() {
    
    
        super.testMethod() // 和Java的用法一样,调用父类Person的方法testMethod
        println("test value is ${
      
      super.test}") // 调用的是父类Person的test
    }
}

fun main(){
    
    
    val man = Man("Tom", 22)
    man.testMethod()
}

Output result:

父类test!
test value is -1

4.2.2 The subclass selectively calls the method of the parent interface/parent class

When a Kotlin class inherits a parent class and multiple interfaces, it is necessary to distinguish superwhich method of the parent class is called. In Kotlin, super<父类/父接口>.方法call the method of the parent class/interface by way

// Australopithecus接口,写法和Java类似
interface Australopithecus{
    
    

    fun testMethod(){
    
    
        println("接口test!")
    }
}

// Person
open class Person {
    
    

    open fun testMethod(){
    
    
        println("父类test!")
    }
}

// Man类,既继承了父类Man,也实现了接口Australopithecus
class Man: Person(), Australopithecus {
    
    

    override fun testMethod() {
    
    
        super<Australopithecus>.testMethod()
        super<Person>.testMethod()
    }
}

fun main(){
    
    
    val man = Man()
    man.testMethod()
}

Output result:

接口test!
父类test!

4.2.3 Subclass inner class calls parent class method

This situation is that the inner class of the subclass calls the method of the parent class, which is written like this:super@子类.方法

// Person
open class Person {
    
    

    open fun testMethod(){
    
    
        println("父类test!")
    }
}

// Man类
class Man: Person() {
    
    

	// 被inner修饰的内部类是非静态内部类,静态内部类显然不能访问非静态内部类的成员方法
    inner class Heart{
    
    
    
        fun testMethod(){
    
    
            super@Man.testMethod()
        }
    }
}

fun main(){
    
    
    Man().Heart().testMethod()
}

Output result:

父类test!

In fact, thisthere is a similar usage in inner classes:

// Man类
class Man {
    
    

    fun eat(){
    
    
        println("eat!")
    }

    inner class Heart{
    
    

        fun testMethod(){
    
    
            this@Man.eat() // 调用外部类的方法,这种操作更加常见
        }
    }
}

fun main(){
    
    
    Man().Heart().testMethod()
}

Output result:

eat!

Remember whether it is superor thisbehind @must be a subclass!

Guess you like

Origin blog.csdn.net/RQ997832/article/details/125155911