继承

Kotlin中所有的类都有共同的父类Any ,默认是缺省父类的,例如:

class Gobj // 隐式继承于 Any

Any不是 java.lang.Object;事实上它除了 equals(),hashCode()以及toString()外没有任何成员了。


声明一个明确的父类,需要在类头后加冒号再加父类:

open class Base(p: Int)

class Derived(p: Int) : Base(p)

如果类有主构造器,则基类可以而且是必须在主构造器中立即初始化。


如果类没有主构造器,每一个二级构造器中不得不用 super 关键字初始化基类,或者再代理另一个构造器做这件事。注意在这种情形中不同的二级构造器可以调用基类不同的构造方法:


class MyView : View {
	constructor(ctx: Context) : super(ctx) {
	}
	constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
	}
}

open 注解与java 中的 final相反:它允许别的类继承这个类。默认情形下,kotlin 中所有的类都是 final ,即不允许继承。

重写方法

像之前提到的,我们在 kotlin 中坚持做明确的事。不像 java ,kotlin 需要把可以重写的成员都明确注解出来,并且重写它们:


open class Base {
	open fun v() {}
	fun nv() {}
}

class Derived() : Base() {
	override fun v() {}
}

对于 Derived.v() 来说 override 注解是必须的。如果没有加的话,编译器会提示。如果没有 open 注解,像 Base.nv() ,在子类中声明一个同样的函数是不合法的,要么加 override 要么不要复写。在 final 类(就是没有open注解的类)中,open 类的成员是禁止的。



标记为 override 的成员是 open的,它可以在子类中被复写。如果你不想被重写就要加 final。

重写属性

重写属性和重写方法一样,父类的属性在子类被重写的时候,必须指定override,并且,必须是兼容的类型。每一个属性都能通过初始化或者getter方法重写。

open class Foo {
    open val x: Int get { ... }
}


class Bar1 : Foo() {
    override val x: Int = ...
}

你也能够用var属性重写一个val属性,但是不是基于变量。允许这样是因为val属性建了一个一个getter方法,并且重写为一个var属性是额外的声明了一个setter方法。


【注意】:你可以在主构造器中用override关键字声明一部分属性。


interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}
重写规则

在 kotlin 中,实现继承通常遵循如下规则:如果一个类从它的直接父类继承了同一个成员的多个实现,那么它必须复写这个成员并且提供自己的实现(或许只是直接用了继承来的实现)。为表示使用父类中提供的方法,我们用 super<Base>表示:


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{
	override fun f() {
		super<A>.f()//调用 A.f()
		super<B>.f()//调用 B.f()
	}
}

可以同时从 A B 中继承方法,而且 C 继承 a() 或 b() 的实现没有任何问题,因为它们都只有一个实现。但是 f() 有俩个实现,因此我们在 C 中必须复写 f() 并且提供自己的实现来消除歧义。

抽象类

一个类或一些成员可能被声明成 abstract 。一个抽象方法在它的类中没有实现方法。记住我们不用给一个抽象类或函数添加 open 注解,它默认是带着的。
我们可以用一个抽象成员去复写一个带 open 注解的非抽象方法。

open class Base {
	open fun f() {}
}

abstract class Derived : Base() {
	override abstract fun f()
}
伴随对象

在 kotlin 中不像 java 或者 C# 它没有静态方法。在大多数情形下,我们建议只用包级别的函数。


如果你要写一个没有实例类就可以调用的方法,但需要访问到类内部(比如说一个工厂方法),你可以把它写成它所在类的一个成员。


更高效的方法是,你可以在你的类中声明一个伴随对象,这样你就可以像 java/c# 那样把它当做静态方法调用,只需要它的类名做一个识别就好了。