Inheritance is one of the three features of object-oriented programming. It is often used in the development process. Inheritance allows a subclass to have the functions of its parent class, and can also enhance and modify the functions of its parent class.
Object-oriented programming is characterized by encapsulation, inheritance and polymorphism
Inheriting ordinary classes
The default class and method in Kotlin are final, so the default cannot be inherited or overridden by subclasses, but can be removed with the open keyword:
- A parent class needs to be open to be inherited
- Superclass methods and attributes need to be open to be overridden
- Overriding a parent member requires the override keyword
open class Person() {
open fun walk(a) {
println("Walk slowly.")}}class Doctor : Person() {
override fun walk(a) {
// super.walk()
println("Walking")}}Copy the code
When a subclass overrides a parent method, it uses the override keyword. In addition, you can use super.xxx() in the body of the overridden method to call the original logic of the parent method, or you can choose to override it completely (super.xxx() is not required). In Kotlin, the parent property is the same as the method. To override a subclass, use the open keyword to modify the parent property and break final:
// Override the parent class attribute
open class Person(open val name: String) {
...
}
class Doctor(override val name: String) : Person(name) {
...
}
Copy the code
Of course, not all subclasses need to override member properties of the parent class, because subclasses access member properties of the parent class through getters/setters. The subclass simply passes the temporary variable (that is, the constructor parameter variable without the val or var modifier) to the parent constructor:
- When you inherit a class, you actually call the superclass constructor
// Pass construction parameters
open class Person(valname: String) {// Val is used, so name is a member attribute of the parent class Person.. }class Doctor(name: String) : Person(name) {// There is no val, so name is just a temporary variable.. }// If you do not want to override the parent attribute, do not use val or var. This is equivalent to defining an attribute in a subclass with the same name as the parent member attribute.
// class Doctor(val name: String) : 'Name' hides memeber of supertype 'Person' and needs 'override' modifier
Copy the code
Inheriting (implementing) Abstract classes (interfaces)
Abstract classes and interfaces are “open” compared to ordinary classes because they are designed to be inherited by subclasses (implementation classes) :
- Interfaces, interface methods, and abstract classes default to open
abstract class Person() {
open fun walk(a){// Member methods that can be overridden by subclasses use the open keyword
println("Walk slowly.")}abstract fun work(a) // Abstract methods are open by default
}
class Doctor : Person() {
override fun walk(a) {
println("Walking")}override fun work(a){// The subclass implements the superclass abstract method, again using the override keyword}}Copy the code
The interface agent
Kotlin doesn’t support multiple inheritance, can only use the interface to implement multiple function, but we don’t want to the realization of the interface methods in the class write death, this code is a flexible enough, therefore, tend to be in the class constructor parameters, the interface implementation class incoming, in our class, only need to realize the method body of the interface method invokes the corresponding methods of implementation class:
interface Driver {
fun dirve(a)
}
class Manager(val driver: Driver) : Driver {
override fun dirve(a) {
driver.dirve()
}
}
Copy the code
Kotlin provides interface proxies that hand the implementation of interface methods directly to the proxy class:
- Format: class XXX(interface implementation class) : interface by interface implementation class
class Manager(driver: Driver): Driver by driver
Copy the code
Does this count as “curvilinear salvation” against Kotlin’s rejection of multiple inheritance? Java does not support multiple inheritance either, and is usually handled in a composite manner.
Interface method conflict
We’ve already seen that interface methods can be implemented by default. Kotlin can implement multiple interfaces that may have the same interface method, as in this example:
interface Radio {
fun display(a): String {
return "107.1"}... }interface Compass {
fun display(a): String {
return "Oriental"}... }Copy the code
If you have an implementation class that implements both interfaces, interface method conflicts will occur:
class Phone(val type: Int) : Radio, Compass {
override fun display(a): String {
return super.display() // IDE error: Many supertypes available, please specify the one you mean in Angle brackets, e.g. 'super
'
}... }Copy the code
We can use a generic name after super to specify the name of the parent class (interface) :
class Phone(val type: Int) : Radio, Compass {
override fun display(a): String {
when (type) {
0 -> return super<Radio>.display()
1 -> return super<Compass>.display()
else -> return "Not supported"}}}Copy the code
If the signature is consistent but the return value is different, the problem will not be solved:
Method signature consistency means that the method name and parameter list are the same.
interface Radio {
fun display(a): String {
return "107.1"}}interface Compass {
fun display(a): Int {
return 180}}// IDE error:
// Platform declaration clash: The following declarations have the same JVM signature (display()Ljava/lang/String;)
// Platform declaration clash: The following declarations have the same JVM signature (display()I;)
class Phone(val type: Int) : Radio, Compass {
override fun display(a): String { / / IDE an error
}
override fun display(a): Int { / / IDE an error}}Copy the code
On the other hand, if the methods return the same value but have different signatures, the situation is different. This is equivalent to two different methods, which need to be overridden separately. However, when calling the interface method with super.xxx(), we still need to use generics to specify the parent interface to avoid ambiguity:
interface Radio {
fun display(a): String {
return "107.1"}}interface Compass {
fun display(i: Int): Int {
return i
}
}
class Phone(val type: Int) : Radio, Compass {
override fun display(a): String {
return super <Radio>.display()
}
override fun display(i: Int): Int {
return super<Compass>.display(i)
}
}
Copy the code