一、Kotlin 中所有类都继承该 Any 类,它是所有类的超类,对于没有超类型声明的类是默认超类。Any默认提供了三个函数:equals()、hashCode()、toString()
二、关于构造函数
-
如果一个子类有主构造函数, 则基类(父类)必须在主构造函数中立即初始化。
//如果一个类要被继承,可以使用 open 关键字进行修饰。
open class Base(p: Int)//Base为基类
class Derived(p: Int) : Base(p)
-
如果类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数:
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
//基类
open class Person(name:String){
//次级构造函数
constructor(name:String,age:Int):this(name){
//初始化
println("基类次级构造函数")
}
}
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("芒果", 21, "111111", 100)
}
//输出:
基类次级构造函数
继承类次级构造函数
学生名: 芒果
年龄: 21
学生号: 111111
成绩: 100
三、关于修饰词
类上的 open 标注与 Java 中 final 相反,它允许其他类从这个类继承。默认情况下,在 Kotlin 中所有的类都是 final
四、覆盖方法(方法重写)
-
Kotlin 力求清晰显式。与 Java 不同,Kotlin 需要显式标注可覆盖的成员(我们称之为开放)和覆盖后的成员,在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,那么就要手动添加 open 修饰它, 子类重写方法使用 override 关键词。
open class Base {
open fun v() {}
fun nv() {}
}
class Derived() : Base() {
override fun v() {}
}
Derived.v() 函数上必须加上 override标注。如果没写,编译器将会报错。 如果函数没有标注 open 如 Base.nv(),则子类中不允许定义相同签名的函数, 不论加不加 override。在一个 final 类中(没有用 open 标注的类),开放成员是禁止的。
标记为 override 的成员本身是开放的,也就是说,它可以在子类中覆盖。如果你想禁止再次覆盖,使用 final 关键字:
open class AnotherDerived() : Base() {
final override fun v() {}
}
五、覆盖属性(属性重写)
属性覆盖与方法覆盖类似;在超类中声明然后在派生类中重新声明的属性必须以override开头
- 能被覆盖的属性必须具有初始化器或者具有 getter 方法
open class Base {
open val x: Int get { …… }//具有初始化程序
}
class Derived : Base() {
override val x: Int = ……//重新声明的属性必须以override开头
}
- 并且它们必须具有兼容的类型。比如说用一个var属性重写一个val属性。但是却不能用一个val属性重写一个var属性。原因是:val不可变 var可变。val具有getter属性,用var去复写的时候就是在基础上增加setter、方法。
open class Base {
open val x: Int //具有getter
}
class Derived : Base() {
override var x: Int =1//用var覆写
}
六、调用超类的实现
- 派生类中的代码可以使用 super 关键字调用其超类的函数与属性访问器的实现:
open class Base {
open fun f() { println("超类.....") }
open val x: Int get() = 1
}
class Derived :Base() {
override fun f() {
super.f()//用super调用超类函数
println("派生类")
}
override val x: Int get() = super.x + 1//用super调用超类属性
}
- 在一个内部类中访问外部类的超类,可以通过由外部类名限定的 super 关键字来实现:super@Outer:
open class Base {
open fun f() { println("超类.....") }
open val x: Int get() = 1
}
class Derived : Base() {
override fun f() { /* …… */ }
override val x: Int get() = 0
inner class InnerClass {
fun g() {
super@Derived.f() // 调用 Base 实现的 f()
println(super@Derived.x) // 使用 Base 实现的 x 的 getter
}
}
}
七、覆盖规则
在 Kotlin 中,实现继承由下述规则规定:如果一个类从它的直接超类继承相同成员的多个实现, 它必须覆盖这个成员并提供其自己的实现(也许用继承来的其中之一)。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如 super<Base>:
//同时继承 A 和 B 没问题,并且 a() 和 b() 也没问题因为 C 只继承了每个函数的一个实现。
// 但是 f() 由 C 继承了两个实现,所以我们必须在 C 中覆盖 f() 并且提供我们自己的实现来消除歧义。
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 {
// 编译器要求覆盖 f():
override fun f() {
super<A>.f() // 调用 A.f()
super<B>.f() // 调用 B.f()
}
}
网友评论