构造函数
通过向 构造函数 传递信息,您可以初始化一个新对象。
每个对象都是一个隔离的世界。程序是对象的集合,因此正确初始化每个单独的对象解决了初始化问题的大部分内容。Kotlin 包括用于确保正确对象初始化的机制。
构造函数类似于一个特殊的成员函数,用于初始化新对象。构造函数的最简单形式是单行类定义:
// Constructors/Wombat.kt
class Wombat
fun main() {
val wombat = Wombat()
}
在 main()
中,调用 Wombat()
创建了一个 Wombat
对象。如果您来自其他面向对象的语言,您可能会期望在这里使用 new
关键字,但在 Kotlin 中,new
是多余的,因此被省略了。
您可以使用参数列表向构造函数传递信息,就像调用函数一样。在这里,Alien
构造函数接受一个参数:
// Constructors/Arg.kt
class Alien(name: String) {
val greeting = "Poor $name!"
}
fun main() {
val alien = Alien("Mr. Meeseeks")
println(alien.greeting)
// alien.name // Error // [1]
}
/* 输出:
Poor Mr. Meeseeks!
*/
创建 Alien
对象需要提供参数(尝试不提供参数)。name
在构造函数内部初始化了 greeting
属性,但在构造函数外部无法访问它 - 尝试取消注释第 [1] 行。
如果您希望构造函数参数在类体外部可访问,请在参数列表中将其定义为 var
或 val
:
// Constructors/VisibleArgs.kt
class MutableNameAlien(var name: String)
class FixedNameAlien(val name: String)
fun main() {
val alien1 =
MutableNameAlien("Reverse Giraffe")
val alien2 =
FixedNameAlien("Krombopolis Michael")
alien1.name = "Parasite"
// 不能这样做:
// alien2.name = "Parasite"
}
这些类定义没有显式的类体 - 类体是隐含的。
当将 name
定义为 var
或 val
时,它将成为一个属性,因此可以在构造函数外部访问。val
构造函数参数无法更改,而 var
构造函数参数是可变的。
您的类可以有多个构造函数参数:
// Constructors/MultipleArgs.kt
class AlienSpecies(
val name: String,
val eyes: Int,
val hands: Int,
val legs: Int
) {
fun describe() =
"$name with $eyes eyes, " +
"$hands hands and $legs legs"
}
fun main() {
val kevin =
AlienSpecies("Zigerion", 2, 2, 2)
val mortyJr =
AlienSpecies("Gazorpian", 2, 6, 2)
println(kevin.describe())
println(mortyJr.describe())
}
/* 输出:
Zigerion with 2 eyes, 2 hands and 2 legs
Gazorpian with 2 eyes, 6 hands and 2 legs
*/
在 复杂构造函数 中,您将看到构造函数还可以包含复杂的初始化逻辑。
如果在预期 String
的地方使用对象,则 Kotlin 会调用对象的 toString()
成员函数。如果您没有编写这个函数,您仍然会得到一个默认的 toString()
:
// Constructors/DisplayAlienSpecies.kt
fun main() {
val krombopulosMichael =
AlienSpecies("Gromflomite", 2, 2, 2)
println(krombopulosMichael)
}
/* 示例输出:
AlienSpecies@4d7e1886
*/
默认的 toString()
并不是很有用 - 它会产生类名和对象的物理地址(这在不同的程序执行之间会有所不同)。您可以定义自己的 toString()
:
// Constructors/Scientist.kt
class Scientist(val name: String) {
override fun toString(): String {
return "Scientist('$name')"
}
}
fun main() {
val zeep = Scientist("Zeep Xanflorp")
println(zeep)
}
/* 输出:
Scientist('Zeep Xanflorp')
*/
override
是一个我们新学的关键字。在这里它是必需的,因为 toString()
已经有了一个定义,即产生原始结果的定义。override
告诉 Kotlin 我们实际上确实想要用我们自己的定义替换默认的 toString()
。override
的明确性可以澄清代码并防止错误。
在对象的内容以方便的形式显示的 toString()
对于查找和修复编程错误很有用。为了简化调试过程,IDE 提供了调试器,允许您观察程序执行的每个步骤,并查看您的对象的内部。
练习和解答可以在 www.AtomicKotlin.com 找到。