接口
Kotlin的接口和Java 8的接口很相似。它们可以包含抽象方法也可以包含方法的实现。与抽象类不同的地方在于,接口不可以存储状态。它们可以拥有属性,但是必须是抽象的或者提供访问器的实现。
使用关键词interface
定义接口:
interface MyInterface {
fun bar()
fun foo() {
// 可选的方法体
}
}
实现接口
一个类或对象,可以实现一个或多个接口
class Child : MyInterface {
override fun bar() {
// body
}
}
接口中的属性
你可以在接口中声明属性,接口中声明的属性可以使抽象的也可以提供访问器的实现。但是声明在接口中的属性,不可以有幕后字段,因此定义在接口中的访问器不能引用它们。
interface MyInterface {
val prop: Int // 抽象属性
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child : MyInterface {
verride val prop: Int = 29
}
解决重写冲突
当我们在超级类型列表中声明多个类型时,会发现我们继承了不止一个相同方法的实现。如:
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()没有用abstract标记,因为在接口中,如果函数没有函数体,那么该函数默认是抽象函数)。现在,如果我们从A类生成一个具体的C类,我们显然需要重写bar()和提供一个实现。
然而,如果我们从A和B类生成一个具体的D类,我们需要实现从多个接口中继承过来的所有方法,而且详细说明D需要怎样完全的实现它们。这个规则用于我们继承的单个实现(bar())和多个实现(foo())方法。
访问修饰符
类、对象、接口、构造函数、函数、属性和它的setter可以有访问修饰符(getter通常和属性有相同的访问属性)。Kotlin中有4个访问修饰符:private、protected、internal和public。如果没有使用显示的修饰符,将会使用默认的访问属性public。
包
函数、属性和类、对象和接口都可以定义在顶层(top-level),即,直接在包内:
// 文件名: example.kt
package foo
fun baz() {} //顶层的函数
class Bar {} //顶层的类
- 如果你没有具体说明任何修饰符,就默认使用public,这样你声明的包,就可以在任何地方被访问。
- 如果你声明为private,那就只能在包含声明的文件内部可以访问。
- 如果你声明为internal,它就可以在同一个模块的任何地方可以访问。
- protected在顶层声明中不可以使用。
如:
// 文件名: example.kt
package foo
private fun foo() {} // foo只在example.kt内可以访问
public var bar: Int = 5 // bar可以在任何地方范文。
private set // setter 只在 example.kt内可以访问
internal val baz = 6// 在相同的模块中可以访问。
类和接口
当在类中声明成员时:
- private 只能在类内部可以访问(包括它所有的成员)。
- protected 不仅可以在类内部访问,还可以在子类中访问。
- internal 在本模块中可以访问到声明类的终端就可以访问到声明的internal成员。
- public 所有可以访问到声明类的终端就可以访问到声明的public成员。
例子:
open class Outer {
private val a = 1
protected open val b = 2
internal val c = 3
val d = 4 // 默认是public
protected class Nested {
public val e: Int = 5
}
}
class Subclass : Outer() {//集成Outer类
// a 不可以访问
// b, c 可以访问
// Nested 和 e 可以访问
override val b = 5 // 'b' 是protected可以被重写
}
class Unrelated(o: Outer) {//引用Outer类
// o.a, o.b 不可以访问
// o.c 和 o.d 可以访问 (相同模块)
// Outer.Nested 不可以访问, 而且 Nested::e 也不可以访问
}
构造函数
使用下面的句法(你需要显示使用关键词constructor)来具体说明类的主构造函数访问权限。
class C private constructor(a: Int) { ... }
这里的构造函数是private。所有的构造函数默认都是public,只要类可以被访问,它的构造函数也就可以被访问。(即,一个internal 类的构造函数只能在相同的模块中访问)。
局部声明
局部声明的变量、函数和类都不可以有访问修饰符。
模块
使用访问修饰符internal表示成员只能在相同的模块中访问。更明确地说,模块就是一系列的Kotlin文件编译在一起。
- 一个IntelliJ IDEA模块
- 一个Maven项目
- 一个Gradle源码集合
- Ant任务执行一次编译的一组文件