[关闭]
@cxm-2016 2016-12-14T11:29:17.000000Z 字数 2322 阅读 1752

Kotlin (十五)——对象

Kotlin

版本:1
翻译:李颖

对象表达式(Object Expression)与对象声明(Object Declaration)

有时我们需要创建一个对象, 这个对象在某个类的基础上略做修改, 但又不希望仅仅为了这一点点修改就明确地声明一个新类.
Java 通过 匿名内部类(anonymous inner class) 来解决这种问题.
Kotlin 使用 对象表达式(object expression)对象声明(object declaration), 对这个概念略做了一点泛化.

对象表达式(Object expression)

要创建一个继承自某个类(或多个类)的匿名类的对象, 我们需要写这样的代码:

  1. window.addMouseListener(object : MouseAdapter() {
  2. override fun mouseClicked(e: MouseEvent) {
  3. // ...
  4. }
  5. override fun mouseEntered(e: MouseEvent) {
  6. // ...
  7. }
  8. })

如果某个基类有构造器, 那么必须向构造器传递适当的参数.
通过冒号之后的逗号分隔的类型列表, 可以指定多个基类:

  1. open class A(x: Int) {
  2. public open val y: Int = x
  3. }
  4. interface B {...}
  5. val ab: A = object : A(1), B {
  6. override val y = 15
  7. }

如果, 我们 "只需要对象", 而不需要继承任何有价值的基类, 我们可以简单地写:

  1. val adHoc = object {
  2. var x: Int = 0
  3. var y: Int = 0
  4. }
  5. print(adHoc.x + adHoc.y)

与 Java 的匿名内部类(anonymous inner class)类似, 对象表达式内的代码可以访问创建这个对象的代码范围内的变量.
(与 Java 不同的是, 被访问的变量不需要被限制为 final 变量.)

  1. fun countClicks(window: JComponent) {
  2. var clickCount = 0
  3. var enterCount = 0
  4. window.addMouseListener(object : MouseAdapter() {
  5. override fun mouseClicked(e: MouseEvent) {
  6. clickCount++
  7. }
  8. override fun mouseEntered(e: MouseEvent) {
  9. enterCount++
  10. }
  11. })
  12. // ...
  13. }

对象声明(Object declaration)

单例模式 是一种非常有用的模式, Kotlin (继 Scala 之后) 可以非常便利地声明一个单例:

  1. object DataProviderManager {
  2. fun registerDataProvider(provider: DataProvider) {
  3. // ...
  4. }
  5. val allDataProviders: Collection<DataProvider>
  6. get() = // ...
  7. }

这样的代码称为一个 对象声明(object declaration), 在 object{: .keyword } 关键字之后必须指定对象名称.
与变量声明类似, 对象声明不是一个表达式, 因此不能用在赋值语句的右侧.

要引用这个对象, 我们直接使用它的名称:

  1. DataProviderManager.registerDataProvider(...)

这样的对象也可以指定基类:

  1. object DefaultListener : MouseAdapter() {
  2. override fun mouseClicked(e: MouseEvent) {
  3. // ...
  4. }
  5. override fun mouseEntered(e: MouseEvent) {
  6. // ...
  7. }
  8. }

注意: 对象声明不可以是局部的(也就是说, 不可以直接嵌套在函数之内), 但可以嵌套在另一个对象声明之内, 或者嵌套在另一个非内部类(non-inner class)之内.

同伴对象(Companion Object)

一个类内部的对象声明, 可以使用 companion{: .keyword } 关键字标记为同伴对象:

  1. class MyClass {
  2. companion object Factory {
  3. fun create(): MyClass = MyClass()
  4. }
  5. }

我们可以直接使用类名称作为限定符来访问同伴对象的成员:

  1. val instance = MyClass.create()

同伴对象的名称可以省略, 如果省略, 则会使用默认名称 Companion:

  1. class MyClass {
  2. companion object {
  3. }
  4. }
  5. val x = MyClass.Companion

注意, 虽然同伴对象的成员看起来很像其他语言中的类的静态成员(static member), 但在运行时期, 这些成员仍然是真实对象的实例的成员, 它们与静态成员是不同的, 举例来说, 它还可以实现接口:

  1. interface Factory<T> {
  2. fun create(): T
  3. }
  4. class MyClass {
  5. companion object : Factory<MyClass> {
  6. override fun create(): MyClass = MyClass()
  7. }
  8. }

但是, 如果使用 @JvmStatic 注解, 你可以让同伴对象的成员在 JVM 上被编译为真正的静态方法(static method)和静态域(static field). 详情请参见 与 Java 的互操作性.

对象表达式与对象声明在语义上的区别

对象表达式与对象声明在语义上存在一个重要的区别:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注