📅  最后修改于: 2021-01-05 08:00:12             🧑  作者: Mango
继承是面向对象编程语言的重要特征。继承允许将现有类(或基类或父类)的功能继承到新类(或派生类或子类)。
主类称为超类(或父类),而继承超类的类称为子类(或子类)。子类包含超类及其自身的功能。
当两个或多个类具有相同的属性时,就可以使用继承的概念。它允许代码可重用。派生类仅具有一个基类,但可以具有多个接口,而基类可以具有一个或多个派生类。
在Kotlin中,派生类使用类标题中的:运算符(在派生类名称或构造函数之后)继承基类。
open class Base(p: Int){
}
class Derived(p: Int) : Base(p){
}
假设我们有两个不同的类“ Programmer”和“ Salesman”,它们具有共同的属性“ name”,“ age”和“ salary”,以及它们各自独立的功能doProgram()和fieldWork()。继承功能使我们可以继承(Employee)包含通用功能。
open class Employee(name: String, age: Int, salary: Float) {
// code of employee
}
class Programmer(name: String, age: Int, salary: Float): Employee(name,age,salary) {
// code of programmer
}
class Salesman(name: String, age: Int, salary: Float): Employee(name,age,salary) {
// code of salesman
}
所有Kotlin类都有一个通用的超类“ Any”。它是没有明确指定超类的类的默认超类。
例如,类Example隐式继承自Any。
class Example
由于默认情况下Kotlin类是final类,因此不能简单地继承它们。我们在类之前使用open关键字来继承类并将其设置为非最终类,
例如:
open class Example{
// I can now be extended!
}
当我们继承一个类以派生类时,所有字段和功能都会被继承。我们可以在派生类中使用这些字段和功能。
例如:
open class Base{
val x = 10
}
class Derived: Base() {
fun foo() {
println("x is equal to " + x)
}
}
fun main(args: Array) {
val derived = Derived()
derived.foo()
}
输出:
x is equal to 10
open class Bird {
fun fly() {
println("flying...")
}
}
class Duck: Bird() {
fun swim() {
println("swimming...")
}
}
fun main(args: Array) {
val duck = Duck()
duck.fly()
duck.swim()
}
输出:
flying...
swimming...
在这里,我们声明一个类Employee为超类,而Programmer和Salesman是其子类。子类继承属性名称,年龄和薪水,并且子类包含其自己的功能,例如doProgram()和fieldWork()。
open class Employee(name: String, age: Int, salary: Float) {
init {
println("Name is $name.")
println("Age is $age")
println("Salary is $salary")
}
}
class Programmer(name: String, age: Int, salary: Float):Employee(name,age,salary){
fun doProgram() {
println("programming is my passion.")
}
}
class Salesman(name: String, age: Int, salary: Float):Employee(name,age,salary){
fun fieldWork() {
println("travelling is my hobby.")
}
}
fun main(args: Array){
val obj1 = Programmer("Ashu", 25, 40000f)
obj1.doProgram()
val obj2 = Salesman("Ajay", 24, 30000f)
obj2.fieldWork()
}
输出:
Name is Ashu.
Age is 25
Salary is 40000.0
programming is my passion.
Name is Ajay.
Age is 24
Salary is 30000.0
travelling is my hobby.
如果在这种情况下,基类和派生类都具有主构造函数,则在基类的主构造函数中初始化参数。在上面的继承示例中,所有类都包含三个参数“ name”,“ age”和“ salary”,并且所有这些参数都在基类的主构造函数中初始化。
当基类和派生类在其主构造函数中都包含不同数量的参数时,则从派生类对象初始化基类参数。
例如:
open class Employee(name: String,salary: Float) {
init {
println("Name is $name.")
println("Salary is $salary")
}
}
class Programmer(name: String, dept: String, salary: Float):Employee(name,salary){
init {
println("Name $name of department $dept with salary $salary.")
}
fun doProgram() {
println("Programming is my passion.")
}
}
class Salesman(name: String, dept: String, salary: Float):Employee(name,salary){
init {
println("Name $name of department $dept with salary $salary.")
}
fun fieldWork() {
println("Travelling is my hobby.")
}
}
fun main(args: Array){
val obj1 = Programmer("Ashu", "Development", 40000f)
obj1.doProgram()
println()
val obj2 = Salesman("Ajay", "Marketing", 30000f)
obj2.fieldWork()
}
输出:
Name is Ashu.
Salary is 40000.0
Name Ashu of department Development with salary 40000.0.
Programming is my passion.
Name is Ajay.
Salary is 30000.0
Name Ajay of department Marketing with salary 30000.0.
Travelling is my hobby.
创建派生类的对象时,它将首先调用其超类并执行基类的init块,然后执行其自身的块。
如果派生类不包含任何主构造函数,则需要使用super关键字从派生类调用基类的辅助构造函数。
例如,
open class Patent {
constructor(name: String, id: Int) {
println("execute super constructor $name: $id")
}
}
class Child: Patent {
constructor(name: String, id: Int, dept: String): super(name, id) {
print("execute child class constructor with property $name, $id, $dept")
}
}
fun main(args: Array) {
val child = Child("Ashu",101, "Developer")
}
输出:
execute super constructor Ashu: 101
execute child class constructor with property Ashu, 101, Developer
在上面的示例中,创建Child类的对象时,它将调用其构造函数并使用值“ Ashu”,“ 101”和“ Developer”初始化其参数。同时,Child类构造函数使用具有name和id值的super关键字调用其超级类构造函数。由于存在super关键字,因此超类构造函数的主体首先执行,然后返回Child类构造函数。
方法覆盖是指将父(父)类的方法的特定实现提供到其子类(子)类。
换句话说,当子类将其超类的方法重新定义或修改为子类时,称为方法重写。方法重写只能在继承中进行。
Kotlin方法重写规则
open class Bird {
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
}
class Duck: Bird() {
}
fun main(args: Array) {
val p = Parrot()
p.fly()
val d = Duck()
d.fly()
}
输出:
Bird is flying...
Bird is flying...
在上面的示例中,一个没有覆盖基类方法的程序,我们发现派生类Parrot和Duck都执行相同的通用操作。为了克服这个问题,我们使用方法覆盖的概念。
在此示例中,父类Bird的fly()方法在其子类Parrot和Duck中被覆盖。要覆盖父类的方法,必须将要覆盖的父类及其方法声明为open 。同时,在子类中被覆盖的方法必须以关键字override作为开头。
open class Bird {
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override fun fly() {
println("Parrot is flying...")
}
}
class Duck: Bird() {
override fun fly() {
println("Duck is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
val d = Duck()
d.fly()
}
输出:
Parrot is flying...
Duck is flying...
与方法类似,超类的属性也可以在其子类中被覆盖。 Bird类的color属性在其子类Parrot和Duck中被覆盖并进行了修改。
open class Bird {
open var color = "Black"
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override var color = "Green"
override fun fly() {
println("Parrot is flying...")
}
}
class Duck: Bird() {
override var color = "White"
override fun fly() {
println("Duck is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
println(p.color)
val d = Duck()
d.fly()
println(d.color)
}
输出:
Parrot is flying...
Green
Duck is flying...
White
我们可以在继承中用var属性覆盖val属性,但反之亦然。
派生类还可以使用super关键字调用其超类方法和属性。
例如:
open class Bird {
open var color = "Black"
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override var color = "Green"
override fun fly() {
super.fly()
println("Parrot is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
println(p.color)
}
输出:
Bird is flying...
Parrot is flying...
Green
在Kotlin中,派生类在实现多个类中提供的相同函数名称时,在尖括号中使用超类型名称,例如gsuper
例如,派生类Parrotextends其超类Bird并实现包含相同函数fly()的Duck接口。要调用每个类和接口的特定方法,我们必须在尖括号中将每个类型的超类型名称称为super
open class Bird {
open var color = "Black"
open fun fly() {
println("Bird is flying...")
}
}
interface Duck {
fun fly() {
println("Duck is flying...")
}
}
class Parrot: Bird(),Duck {
override var color = "Green"
override fun fly() {
super.fly()
super.fly()
println("Parrot is flying...")
}
}
fun main(args: Array) {
val p = Parrot()
p.fly()
println(p.color)
}
输出:
Bird is flying...
Duck is flying...
Parrot is flying...