1. 概述
在本教程中,我们将深入探讨 Kotlin 中的构造函数。
首先快速回顾一下概念:构造函数用于创建对象。它们看起来像方法声明,但名称始终与类名一致,并且不返回任何值。
如果你需要搭建 Kotlin 项目,可以参考我们的 Kotlin 入门指南。
✅ 在 Kotlin 中,一个类可以有一个主构造函数(primary constructor)和一个或多个次构造函数(secondary constructor)。
接下来的章节中,我们会逐一介绍每种构造函数及其相关特性。
2. 主构造函数(Primary Constructor)
Kotlin 中创建对象的第一种方式就是使用主构造函数。
⚠️ 主构造函数是类头的一部分。参数也可以直接作为类的属性,紧跟在类声明之后。
来看一个简单的类定义示例,包含两个属性和一个主构造函数:
class Person constructor(val name: String, val age: Int? = null)
在这个例子中,我们通过 val
关键字声明了属性。这和普通变量的行为类似,只不过 val
声明的是只读属性(相当于 Java 中的 final
)。
如果后续需要修改引用,应该使用 var
关键字。不过,主构造函数中的字段类型不能省略,必须显式声明。
⚠️ 在某些情况下,我们可以省略 constructor
关键字。只有在使用注解(如 @Autowired
)或访问修饰符(如 private
或 protected
)时,才必须显式写出。
此外,Kotlin 的主构造函数支持默认参数。
接下来,看看如何使用主构造函数:
val person = Person("John")
val personWithAge = Person("Mark", 22)
可以看到,类名就是构造函数调用,无需使用 new
关键字。
作为对比,下面是 Java 中等价的构造函数实现:
class PersonJava {
final String name;
final Integer age;
public PersonJava(String name) {
this.name = name;
this.age = null;
}
public PersonJava(String name, Integer age) {
this.name = name;
this.age = age;
}
}
显然,Java 要实现相同的功能需要更多的代码。
2.1. JVM 上的主构造函数
请注意,编译器会在 JVM 上生成一个无参构造函数,用于初始化默认值。
这样,Kotlin 就能很好地与 Jackson、JPA 等依赖无参构造函数来创建类实例的库配合使用:
class Person(val name: String = "")
3. 从构造参数初始化属性
✅ 类体中的属性初始化器可以使用主构造函数的参数。
比如,将 name
转换为大写形式的 upperCaseName
属性:
class Person(val name: String, val age: Int? = null) {
val upperCaseName: String = name.toUpperCase()
}
我们可以通过添加 init
块来在控制台输出结果:
init {
println("Upper case name is $upperCaseName")
}
4. 初始化块(Initializer Blocks)
⚠️ 主构造函数中不能直接写执行代码。
但有时我们需要执行一些初始化逻辑,这时候就可以使用初始化块,以 init
关键字开头。
✅ 初始化块在主构造函数之后执行,并且可以访问类的字段。
一个类可以有多个 init
块。
给 Person
类添加一个初始化块:
init {
println("Hello, I'm $name")
if (surname.isEmpty()) {
throw IllegalArgumentException("Surname cannot be empty!")
}
}
创建 Person
对象时,控制台将输出:
Hello, I'm John
如果 surname
为空,会抛出 IllegalArgumentException
异常。
多个 init
块会按照它们在类体中出现的顺序依次执行。
5. 次构造函数(Secondary Constructor)
在 Kotlin 类中,我们还可以定义一个或多个次构造函数。✅ 次构造函数以 constructor
关键字开头:
class Car {
val id: String
val type: String
constructor(id: String, type: String) {
this.id = id
this.type = type
}
}
使用方式如下:
fun main(args: Array<String>) {
val car = Car("1", "sport")
val suvCar = Car("2", "suvCar")
}
⚠️ 每个次构造函数都必须委托给主构造函数,通过 this
关键字实现。
我们将属性移到主构造函数中,修改次构造函数如下:
class Car(val id: String, val type: String) {
constructor(id: String): this(id, "unknown")
}
6. 构造函数与继承
我们可以使用父类的主构造函数。
注意,Kotlin 中所有类默认是 final
的。因此,如果希望某个类能被继承,需要加上 open
关键字。
比如定义一个继承自 Person
的 Employee
类,两者都使用主构造函数:
class Employee(name: String, val salary: Int): Person(name)
这样我们就把 name
传递给了 Person
的主构造函数,同时在 Employee
中新增了 salary
字段。
7. 总结
在这篇文章中,我们探讨了 Kotlin 中构造函数的各种用法。根据需求,我们可以灵活地初始化字段。
所有示例的完整实现可以在 GitHub 项目 中找到。
如需了解更多 Kotlin 特性,请查看我们的 Kotlin 入门指南。