Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

构造函数

通过向 构造函数 传递信息,您可以初始化一个新对象。

每个对象都是一个隔离的世界。程序是对象的集合,因此正确初始化每个单独的对象解决了初始化问题的大部分内容。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] 行。

如果您希望构造函数参数在类体外部可访问,请在参数列表中将其定义为 varval

// 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 定义为 varval 时,它将成为一个属性,因此可以在构造函数外部访问。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 找到。