可见性修饰符
类、对象、接口、构造函数、函数,以及属性及其 setter
都可以有可见性修饰符。getter
的可见性始终与其所属属性的可见性相同。
有四种可见性修饰符:private
、protected
、internal
和 public
。默认的可见性是 public
。
在本文章中,你将了解这些修饰符如何应用于不同类型的声明作用域。
包
函数、属性、类、对象和接口可以在包内的顶级位置直接声明:
// 文件名:example.kt
package foo
fun baz() { ... }
class Bar { ... }
-
如果你不使用可见性修饰符,默认会使用
public
,这意味着你的声明在任何地方都可见。 -
如果你将一个声明标记为
private
,那么它仅在包含该声明的文件内部可见。 -
如果你将其标记为
internal
,那么它在同一个模块内的任何地方都可见。 -
protected
修饰符不能用于顶级声明。
要从另一个包中使用可见的顶级声明,你需要导入它。
// 文件名:example.kt
package foo
private fun foo() { ... } // 该函数仅在 example.kt 文件内部可见。
public var bar: Int = 5 // 该属性在任何地方都可见。
private set // 该属性的 setter 仅在 example.kt 文件内部可见。
internal val baz = 6 // 该属性在同一个模块内可见。
类成员
对于在类内部声明的成员:
-
private
表示该成员仅在这个类内部可见(包括该类的所有成员)。 -
protected
表示该成员的可见性与标记为private
的成员相同,但在子类中也可见。 -
internal
表示在同一个模块内,任何能看到声明该成员的类的客户端,也能看到其internal
成员。 -
public
表示任何能看到声明该成员的类的客户端,都能看到其public
成员。
在 Kotlin
中,外部类无法访问其内部类的 private
成员。
如果你重写了一个 protected
或 internal
的成员,并且没有显式指定可见性,那么重写后的成员将与原成员具有相同的可见性。
open class Outer {
// 私有属性 a,仅在 Outer 类内部可见。
private val a = 1
// 受保护的开放属性 b,在 Outer 类内部和其子类中可见,且可被子类重写。
protected open val b = 2
// 内部开放属性 c,在同一模块内,能看到 Outer 类的地方都可见,且可被子类重写。
internal open val c = 3
// 属性 d,默认是 public,在任何能看到 Outer 类的地方都可见。
val d = 4
// 受保护的嵌套类 Nested,在 Outer 类内部和其子类中可见。
protected class Nested {
// 公共属性 e,在能看到 Nested 类的地方都可见。
public val e: Int = 5
}
}
class Subclass : Outer() {
// 属性 a 不可见,因为它是 Outer 类的私有属性。
// 属性 b、c 和 d 可见,b 受保护,c 是内部属性,d 是公共属性。
// 嵌套类 Nested 和其属性 e 可见,因为 Nested 是受保护的,子类可访问。
// 重写属性 b,重写后的 b 仍然是受保护的。
override val b = 5
// 重写属性 c,重写后的 c 仍然是内部属性。
override val c = 7
}
// 定义一个不相关的类 Unrelated,其构造函数接收一个 Outer 类的实例。
class Unrelated(o: Outer) {
// o.a 和 o.b 不可见,a 是私有属性,b 是受保护属性。
// o.c 和 o.d 可见(在同一模块内),c 是内部属性,d 是公共属性。
// Outer.Nested 不可见,Nested 类的属性 e 也不可见,因为 Nested 是受保护的。
}
构造函数
可以使用以下语法来指定类主构造函数的可见性,此时需要显式添加 constructor
关键字。
class C private constructor(a: Int) { ... }
在上述代码中,构造函数是 private
。默认情况下,所有构造函数都是 public
,这实际上意味着只要类是可见的,其构造函数在任何地方都能被访问(也就是说,internal
类的构造函数仅在同一模块内可见)。
对于密封类,其构造函数默认是 protected
修饰的。
局部声明
局部变量、函数和类不能使用可见性修饰符。
模块
internal
可见性修饰符表示该成员在同一个模块内可见。
更具体地说,一个模块是一组一起编译的 Kotlin
文件,例如:
-
一个
IntelliJ IDEA
模块。 -
一个
Maven
项目。 -
一个
Gradle
源集(不过test
源集可以访问main
源集的internal
声明)。 -
通过一次
<kotlinc>
Ant
任务调用编译的一组文件。