Kotlin 2.1.0 入门教程(十七)接口
接口
接口可以包含抽象方法的声明,也可以包含方法的实现。
接口与抽象类的不同之处在于,接口无法存储状态。接口可以拥有属性,但这些属性要么必须是抽象的,要么就得提供访问器的实现。
接口使用 interface
关键字来定义:
interface MyInterface {
fun bar()
fun foo() {
// 可选函数体。
}
}
实现接口
一个类或对象可以实现一个或多个接口:
class Child : MyInterface {
override fun bar() {
}
}
接口中的属性
你可以在接口中声明属性。接口中声明的属性可以是抽象的,也可以为访问器提供实现。接口中声明的属性不能有幕后字段,因此接口中声明的访问器也不能引用它们:
interface MyInterface {
// 抽象属性。
var prop: Int
val prop2: String
get() = "foo"
var prop3: String
get() = "foo"
set(value) {
println(value)
}
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override var prop: Int = 29
}
fun main() {
val child = Child()
child.prop = 10
child.prop3 = "aaa" // aaa
}
接口继承
一个接口可以从其他接口派生,这意味着它既可以为其他接口的成员提供实现,也可以声明新的函数和属性。很自然地,实现这样一个接口的类只需要定义缺失的实现:
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
override val firstName: String,
override val lastName: String,
val position: Position
) : Person
解决覆盖冲突
当你在超类型列表中声明多个类型时,你可能会继承同一个方法的多种实现:
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super<B>.bar()
}
}
接口 A
和 B
都声明了函数 foo()
和 bar()
。它们都实现了 foo()
方法,但只有 B
实现了 bar()
方法(A
中的 bar()
没有标记为抽象方法,因为在接口中如果函数没有方法体,默认就是抽象的)。现在,如果你从 A
派生出一个具体类 C
,你就必须重写 bar()
方法并提供实现。
然而,如果你从 A
和 B
派生出类 D
,你需要实现从多个接口继承来的所有方法,并且需要明确指定 D
应该如何实现这些方法。这条规则既适用于你只继承了一种实现的方法(如 bar()
),也适用于你继承了多种实现的方法(如 foo()
)。
和 B
派生出类 D
,你需要实现从多个接口继承来的所有方法,并且需要明确指定 D
应该如何实现这些方法。这条规则既适用于你只继承了一种实现的方法(如 bar()
),也适用于你继承了多种实现的方法(如 foo()
)。