Kotlin 构造函数
- 构造函数类型:Kotlin 提供两种类型的构造函数,主构造函数用于简化类属性初始化,而次级构造函数允许额外的初始化逻辑。
- 主构造函数的使用:主构造函数是类头的一部分,可声明类属性。它支持初始化器块(
init
)用于放置初始化代码,并可为构造函数参数提供默认值。 - 次级构造函数的特点:次级构造函数使用
constructor
关键字定义,用于类扩展和多种初始化方式。它们必须直接或间接地初始化基类,并可通过this()
调用同一类中的另一个构造函数。
构造函数是初始化类属性的简洁方式。
它是在实例化(创建)对象时调用的特殊成员函数。然而,Kotlin 中的构造函数工作方式略有不同。
在 Kotlin 中,有两种构造函数:
- 主构造函数 - 初始化类的简洁方式
- 次级构造函数 - 允许你添加额外的初始化逻辑
主构造函数
主构造函数是类头的一部分。这里有一个例子:
class Person(val firstName: String, var age: Int) {
// 类体
}
括号内的代码块是主构造函数:(val firstName: String, var age: Int)
。
构造函数声明了两个属性:firstName
(只读属性,因为它使用关键字 val
声明)和 age
(可读写属性,因为它使用关键字 var
声明)。
示例:主构造函数
fun main(args: Array<String>) {
val person1 = Person("Joe", 25)
println("First Name = ${person1.firstName}")
println("Age = ${person1.age}")
}
class Person(val firstName: String, var age: Int) {
}
当你运行程序时,输出将是:
First Name = Joe
Age = 25
当创建 Person
类的对象时,"Joe"
和 25
值就好像 Person
是一个函数一样被传递。
这将 person1
对象的 firstName
和 age
属性分别初始化为 "Joe"
和 25
。
还有其他使用主构造函数的方法。
主构造函数和初始化器块
主构造函数的语法受限,不能包含任何代码。
为了放置初始化代码(不仅是初始化属性的代码),使用初始化器块。它以 init
关键字为前缀。让我们用初始化器块修改上面的示例:
fun main(args: Array<String>) {
val person1 = Person("joe", 25)
}
class Person(fName: String, personAge: Int) {
val firstName: String
var age: Int
// 初始化器块
init {
firstName = fName.capitalize()
age = personAge
println("First Name = $firstName")
println("Age = $age")
}
}
当你运行程序时,输出将是:
First Name = Joe
Age = 25
这里,括号内的参数 fName
和 personAge
分别接受值 "Joe"
和 25
,当创建 person1
对象时。然而,fName
和 personAge
没有使用 var
或 val
,并不是 Person
类的属性。
Person
类有两个属性 firstName
和 age
被声明。
当创建 person1
对象时,初始化块内的 代码被执行。初始化块不仅初始化其属性,还打印它们。
以下是执行相同任务的另一种方式:
fun main(args: Array<String>) {
val person1 = Person("joe", 25)
}
class Person(fName: String, personAge: Int) {
val firstName = fName.capitalize()
var age = personAge
// 初始化块
init {
println("姓名 = $firstName")
println("年龄 = $age")
}
}
为了区分构造函数参数和属性,使用了不同的名称(fName
和 firstName
,以及 personAge
和 age
)。通常使用 _firstName
和 _age
而不是为构造函数参数使用完全不同的名称。例如:
class Person(_firstName: String, _age: Int) {
val firstName = _firstName.capitalize()
var age = _age
// 初始化块
init {
... .. ...
}
}
主构造函数中的默认值
你可以为构造函数参数提供默认值(类似于为函数提供默认参数)。例如:
fun main(args: Array<String>) {
println("person1 被实例化")
val person1 = Person("joe", 25)
println("person2 被实例化")
val person2 = Person("Jack")
println("person3 被实例化")
val person3 = Person()
}
class Person(_firstName: String = "UNKNOWN", _age: Int = 0) {
val firstName = _firstName.capitalize()
var age = _age
// 初始化块
init {
println("姓名 = $firstName")
println("年龄 = $age\n")
}
}
当你运行程序时,输出将是:
姓名 = Joe
年龄 = 25
person2 被实例化
姓名 = Jack
年龄 = 0
person3 被实例化
姓名 = UNKNOWN
年龄 = 0
Kotlin 次构造函数
在 Kotlin 中,一个类也可以包含一个或多个次构造函数。它们是使用 constructor
关键字创建的。
次构造函数在 Kotlin 中不那么常见。次构造函数最常见的用途出现在你需要扩展一个提供多个初始化类的不同方式的构造函数的类时。在学习之前,请确保查看 Kotlin 继承。
以下是在 Kotlin 中创建次构造函数的方式:
class Log {
constructor(data: String) {
// 一些代码
}
constructor(data: String, numberOfData: Int) {
// 一些代码
}
}
在这里,Log
类有两个次级构造函数,但没有主构造函数。
你可以这样扩展类:
class Log {
constructor(data: String) {
// 代码
}
constructor(data: String, numberOfData: Int) {
// 代码
}
}
class AuthLog: Log {
constructor(data: String): super(data) {
// 代码
}
constructor(data: String, numberOfData: Int): super(data, numberOfData) {
// 代码
}
}
这里,派生类 AuthLog
的构造函数调用基类 Log
的相应构造函数。为此,使用了 super()
。
在 Kotlin 中,你也可以像在 Java 中一样,使用 this()
从同一类的另一个构造函数调用构造函数。
class AuthLog: Log {
constructor(data: String): this(data, 10) {
// 代码
}
constructor(data: String, numberOfData: Int): super(data, numberOfData) {
// 代码
}
}