Kotlin super 关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的继承系统允许类扩展父类的功能。super
关键字对于访问父类成员至关重要。本教程通过实际例子深入探讨了 super
关键字。
基本定义
Kotlin 中的 super
关键字指的是当前类的父类。它用于访问父类的属性、方法和构造函数。当重写方法或处理继承层次结构时,super
尤其重要。
访问父类属性
当子类具有与父类同名的属性时,super
关键字可以访问父类的属性。这有助于避免继承场景中的命名冲突。
package com.zetcode open class Vehicle { open val speed = 100 } class Car : Vehicle() { override val speed = 120 fun showSpeed() { println("Car speed: $speed") println("Parent speed: ${super.speed}") } } fun main() { val car = Car() car.showSpeed() }
在这里,我们定义了一个具有 speed 属性的 Vehicle 类。Car 类重写了这个属性。使用 super.speed
,我们访问父类的 speed 值。输出显示了子类和父类的属性值。
调用父类方法
当重写方法时,您可以使用 super
调用父类的实现。这允许扩展父类的功能,同时保持原始行为。
package com.zetcode open class Animal { open fun makeSound() { println("Animal makes a sound") } } class Dog : Animal() { override fun makeSound() { super.makeSound() println("Dog barks: Woof!") } } fun main() { val dog = Dog() dog.makeSound() }
Dog 类重写了 makeSound 方法,但首先使用 super.makeSound
调用父类的实现。这演示了如何扩展而不是替换父类功能。
父类构造函数初始化
super
关键字用于从子类构造函数调用父类构造函数。这确保了继承层次结构的正确初始化。
package com.zetcode open class Person(val name: String) { init { println("Person initialized: $name") } } class Employee(name: String, val position: String) : Person(name) { init { println("Employee initialized: $name, $position") } } fun main() { val emp = Employee("John Doe", "Developer") }
在这里,Employee 类使用 : Person(name)
调用 Person 构造函数。此语法隐式地使用 super
来初始化父类。输出显示了从父类到子类的初始化顺序。
使用接口的多重继承
当使用具有冲突方法名称的多个接口时,带有尖括号的 super
指定要调用的父接口。这解决了多重继承中的歧义。
package com.zetcode interface A { fun foo() { println("A's foo") } } interface B { fun foo() { println("B's foo") } } class C : A, B { override fun foo() { super<A>.foo() super<B>.foo() println("C's foo") } } fun main() { val c = C() c.foo() }
C 类实现了接口 A 和 B,它们具有冲突的 foo 方法。使用 super<A>.foo
和 super<B>.foo
,我们显式地调用每个接口的实现。输出显示了所有三个方法调用。
在嵌套类中访问父类
在嵌套类场景中,super
可以使用限定 this 语法访问外部类的父类。这对于复杂的类层次结构很有用。
package com.zetcode open class Outer { open val value = 10 inner class Inner { fun showValues() { println("Inner value: ${this@Outer.value}") println("Parent value: ${super@Outer.value}") } } } class Subclass : Outer() { override val value = 20 } fun main() { val outer = Subclass() val inner = outer.Inner() inner.showValues() }
Inner 类可以使用限定的 super
访问 Subclass 中重写的值和 Outer 中的原始值。输出演示了如何在复杂的继承链中导航。
使用 super 的构造函数委托
在次级构造函数中,super
可以委托给特定的父类构造函数。这提供了对象初始化的灵活性。
package com.zetcode open class Parent { constructor(message: String) { println("Parent primary: $message") } constructor(num: Int) { println("Parent secondary: $num") } } class Child : Parent { constructor(message: String) : super(message) { println("Child primary: $message") } constructor(num: Int) : super(num) { println("Child secondary: $num") } } fun main() { val c1 = Child("Hello") val c2 = Child(42) }
Child 类有两个构造函数,它们使用 super
委托给不同的 Parent 构造函数。每个初始化路径都会产生不同的输出,展示了构造函数委托的实际应用。
使用 super 重写属性
当使用自定义 getter 重写属性时,super
可以访问原始属性值。这允许修改父类的行为,同时保留对原始值的访问。
package com.zetcode open class Shape { open val area: Double = 0.0 } class Circle(val radius: Double) : Shape() { override val area: Double get() = super.area + (Math.PI * radius * radius) } fun main() { val circle = Circle(5.0) println("Circle area: ${circle.area}") }
Circle 类重写了 area 属性,但在其计算中使用 super.area
引用父类的值。这演示了如何基于父类属性构建而不是完全替换它们。
使用 super 的最佳实践
- 谨慎使用: 仅当您需要显式引用父类成员时才使用
super
。 - 构造函数链: 通过调用适当的父类构造函数来确保正确的构造函数初始化。
- 接口冲突: 使用
super<Type>
语法解决多重继承中的方法冲突。 - 文档重写: 清楚地记录您何时以及为什么调用父类实现。
- 避免深层层次结构: 具有频繁 super 调用的深层继承链会使代码更难以维护。
来源
本教程深入介绍了 Kotlin 的 super
关键字,展示了它在继承场景中的各种用法。我们探讨了属性访问、方法重写、构造函数初始化和多重继承解析。正确使用 super
有助于创建可维护的类层次结构。
作者
列出 所有 Kotlin 教程。