Kotlin 的接口
Kotlin 的接口可以包含抽象方法的声明也可以包含实现。接口中可以有属性,但是属性默认情况下,要么是抽象的,无法赋值;要么是只读变量,同时提供getter。接口中的属性不能有幕后字段field 。
interface MyInterface {// 抽象变量var name: String// 只读变量,同时提供getterval propertyWithImplementation: Stringget() = "foo"fun bar()fun foo() {println(name)}}class MyClass : MyInterface {// 在实现类中,实现 nameoverride var name: String = "Ricky"// 在实现类中,实现抽象方法override fun bar() {println("bar...")}}fun main() {val myClass = MyClass()myClass.foo()myClass.bar()println(myClass.propertyWithImplementation)println(myClass.name)}
接口继承
一个接口可以从其他接口继承,从而既可以提供父接口成员的实现,也可以声明新的函数与属性。
interface Named {val name: String}interface Person : Named {val firstName: Stringval lastName: Stringoverride val name: String get() = "$firstName $lastName"}data class Employee(// 不必实现“name”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()}}
上面代码中, 类 D 实现了 A和B接口,同时 A 和 B都是实现了相同的方法 foo(),当我们在类D中想同时调用 A和B接口中的 foo() 方法,那么我们可以通过 super<接口名> 的方式调用指定接口的方法。
可见性修饰符
可见性修饰符类、对象、接口、构造函数、方法、属性和它们的 setter 都可以有 可见性修饰符。(getter 总是与属性有着相同的可见性。)
Kotlin 中有四个可见性修饰符:private、 protected、 internal 和 public。
下面介绍修饰符如何应用到不同类型的声明作用域。
包
函数、属性和类、对象和接口可以在顶层声明,即直接在包内:
// 文件名:example.ktpackage foofun baz() { …… }class Bar { …… }
- 如果你不指定任何可见性修饰符,默认为
public,这意味着你的声明将随处可见; - 如果你声明为
private,它只会在声明它的文件内可见; - 如果你声明为
internal,它会在相同模块内随处可见; protected不适用于顶层声明。
注意:要使用另一包中可见的顶层声明,仍需将其导入进来。
// 文件名:example.ktpackage fooprivate fun foo() { …… } // 在 example.kt 内可见public var bar: Int = 5 // 该属性随处可见private set // setter 只在 example.kt 内可见internal val baz = 6 // 相同模块内可见
类和接口
对于类内部声明的成员:
private:使用private修饰的成员只在本类内部(包含其所有成员)可见;protected:使用protected修饰的成员只在本类内部(包含其所有成员)可见;同时也可以在子类中可见;internal—— 使用internal声明的成员在同一个模块中可见;public—— 使用public声明的成员可以在任何可以引用到该类的地方使用。
请注意在 Kotlin 中,外部类不能访问内部类的 private 成员。
如果你覆盖一个 protected 成员并且没有显式指定其可见性,该成员还会是 protected 可见性。
例如:
open class Outer {private val a = 1protected open val b = 2internal val c = 3val d = 4 // 默认 publicprotected class Nested {public val e: Int = 5}}class Subclass : Outer() {// a 不可见// b、c、d 可见// Nested 和 e 可见override val b = 5 // “b”为 protected}class Unrelated(o: Outer) {// o.a、o.b 不可见// o.c 和 o.d 可见(相同模块)// Outer.Nested 不可见,Nested::e 也不可见}
构造函数
默认情况下所有的构造函数都是 public 的,只要类可以被引用的地方都是可见的。如果要修改主构造函数的可见性,可以在类头中添加 可见性修饰符 + constructor 。如下:
class C private constructor(a: Int) { …… }
代码中的主构造函数是私有的。
局部声明
局部变量、函数和类不能有可见性修饰符。它们只在作用域内有效。
模块
可见性修饰符 internal 意味着该成员只在相同模块内可见。更具体地说, 一个模块是编译在一起的一套 Kotlin 文件:
- 一个 IntelliJ IDEA 模块;
- 一个 Maven 项目;
- 一个 Gradle 源集(例外是
test源集可以访问main的 internal 声明); - 一次
<kotlinc>Ant 任务执行所编译的一套文件。
在接口中可以定义属性,但是该属性是抽象的。
