Kotlin 语言参考文档 中文版 Help

Kotlin 中的类使用 class 关键字定义:

class Person { /*...*/ }

类的定义由以下几部分组成: 类名, 类头部(指定类的类型参数, 主构造器, 以及其他内容), 以及由大括号括起的类主体部分. 类的头部和主体部分都是可选的; 如果类没有主体部分, 那么大括号也可以省略.

class Empty

构造器

Kotlin 中的类有一个 主构造器(primary constructor), 此外还可以有一个或多个 次构造器(secondary constructor). 主构造器在类头部中声明, 位于类名称以及可选的类型参数之后.

class Person constructor(firstName: String) { /*...*/ }

如果主构造器没有任何注解(annotation), 也没有任何可见度修饰符, 那么 constructor 关键字可以省略:

class Person(firstName: String) { /*...*/ }

主构造器初始化类的实例, 以及它在类头部中的属性. 类头部不能包含任何可执行的代码. 如果你想要在对象创建时运行某些代码, 可以使用类 body 中的 初始化代码段(initializer block). 初始化代码段使用 init 关键字来定义, 之后是大括号. 请将你想要运行的代码放在大括号之内.

在类的实例初始化过程中, 初始化代码段按照它们在类主体中出现的顺序执行, 初始化代码段之间还可以插入属性的初始化代码:

//sampleStart class InitOrderDemo(name: String) { val firstProperty = "First property: $name".also(::println) init { println("First initializer block that prints $name") } val secondProperty = "Second property: ${name.length}".also(::println) init { println("Second initializer block that prints ${name.length}") } } //sampleEnd fun main() { InitOrderDemo("hello") }

主构造器的参数可以在初始化代码段中使用. 也可以在类主体定义的属性初始化代码中使用:

class Customer(name: String) { val customerKey = name.uppercase() }

Kotlin 有一种简洁语法, 可以通过主构造器来定义属性并初始化属性值:

class Person(val firstName: String, val lastName: String, var age: Int)

这种声明还可以包含类属性的默认值:

class Person(val firstName: String, val lastName: String, var isEmployed: Boolean = true)

声明类的属性时, 可以使用 尾随逗号(trailing comma):

class Person( val firstName: String, val lastName: String, var age: Int, // 尾随逗号(trailing comma) ) { /*...*/ }

与通常的属性一样, 主构造器中定义的属性可以是可变的(var), 也可以是只读的(val).

如果构造器有注解, 或者有可见度修饰符, 这时 constructor 关键字是必须的, 注解和修饰符要放在它之前:

class Customer public @Inject constructor(name: String) { /*...*/ }

详情请参见 可见度修饰符.

次级构造器(secondary constructor)

类还可以声明 次级构造器(secondary constructor), 使用 constructor 关键字作为前缀:

class Person(val pets: MutableList<Pet> = mutableListOf()) class Pet { constructor(owner: Person) { owner.pets.add(this) // 将这个 pet 实例添加到它的主人的 pet 列表 } }

如果类有主构造器, 那么每个次级构造器都必须委托给主构造器, 要么直接委托, 要么通过其他次级构造器间接委托. 委托到同一个类的另一个构造器时, 使用 this 关键字实现:

class Person(val name: String) { val children: MutableList<Person> = mutableListOf() constructor(name: String, parent: Person) : this(name) { parent.children.add(this) } }

初始化代码段中的代码实际上会成为主构造器的一部分. 在访问次级构造器的第一条语句时, 会执行对主构造器的委托调用, 因此所有初始化代码段中的代码, 以及属性初始化代码, 都会在次级构造器的函数体之前执行.

即使类没有定义主构造器, 也会隐含地委托调用主构造器, 因此初始化代码段仍然会被执行:

//sampleStart class Constructors { init { println("Init block") } constructor(i: Int) { println("Constructor $i") } } //sampleEnd fun main() { Constructors(1) }

如果一个非抽象类没有声明任何主构造器和次级构造器, 它将带有一个自动生成的, 无参数的主构造器. 这个构造器的可见度为 public.

如果不希望你的类带有 public 的构造器, 可以声明一个空的构造器, 并明确设置其可见度:

class DontCreateMe private constructor() { /*...*/ }

创建类的实例

要创建一个类的实例, 需要调用类的构造器, 调用方式与使用通常的函数一样. 你可以将创建的类实例赋值给一个 变量:

val invoice = Invoice() val customer = Customer("Joe Smith")

关于嵌套类, 内部类, 以及匿名内部类的实例创建过程, 请参见嵌套类(Nested Class).

类成员

类中可以包含以下内容:

继承

类可以相互继承, 构成类的继承层级结构. 详情请参加 Kotlin 中的继承.

抽象类

类本身, 或类中的部分成员, 都可以声明为 abstract 的. 抽象成员在类中不存在具体的实现. 你不必对抽象类或抽象成员标注 open 修饰符.

abstract class Polygon { abstract fun draw() } class Rectangle : Polygon() { override fun draw() { // 描绘长方形 } }

你可以使用抽象成员来覆盖一个非抽象的 open 成员:

open class Polygon { open fun draw() { // 某种默认的多边形描绘方法 } } abstract class WildShape : Polygon() { // 从 WildShape 继承的类需要实现自己的 draw 方法, // 而不是使用 Polygon 中的默认方法 abstract override fun draw() }

同伴对象(Companion Object)

如果你需要写一个函数, 希望使用者不必通过类的实例来调用它, 但又需要访问类的内部信息(比如, 一个工厂方法), 你可以将这个函数写为这个类之内的一个 对象声明 的成员, 而不是类本身的成员.

具体来说, 如果你在类中声明一个 同伴对象, 那么只需要使用类名作为限定符就可以访问同伴对象的成员了.

最终更新: 2024/12/17