参考:

对象表达式和声明(Object Expressions and Declarations)

对象表达式(Object expressions)

Object表达式可以创建匿名类:

    window.addMouseListener(object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            // ...
        }

        override fun mouseEntered(e: MouseEvent) {
            // ...
        }
    })

与Java匿名类不同的是,Java仅仅只能使用已有类型进行实例化,Kotlin可以在实例化匿名类时对匿名类进行定义,也就是说匿名类不用使用已有类型,如下所示:

继承已有的类型:

    open class A(x: Int) {
        public open val y: Int = x
    }

    interface B {...}

    val ab: A = object : A(1), B {
        override val y = 15
    }

或者不继承已有的类,默认继承Any:

    fun foo() {
        val adHoc = object {
            var x: Int = 0
            var y: Int = 0
        }
        print(adHoc.x + adHoc.y)
    }

匿名类对象的类型信息只存在于本地和private声明中,如果匿名类对象可以通过public方法或属性公开访问,那么外部看到的类型是其超类或者Any。

    class C {
        // Private function, so the return type is the anonymous object type
        private fun foo() = object {
            val x: String = "x"
        }

        // Public function, so the return type is Any
        fun publicFoo() = object {
            val x: String = "x"
        }

        fun bar() {
            val x1 = foo().x        // Works
            val x2 = publicFoo().x  // ERROR: Unresolved reference 'x'
        }
    }

与Java中匿名内部类不能直接访问包围类的变量不一样,Kotlin中的object表达式可以直接访问这些变量,而且不限定变量是否是final的:

    fun countClicks(window: JComponent) {
        var clickCount = 0
        var enterCount = 0

        window.addMouseListener(object : MouseAdapter() {
            override fun mouseClicked(e: MouseEvent) {
                clickCount++
            }

            override fun mouseEntered(e: MouseEvent) {
                enterCount++
            }
        })
        // ...
    }

对象声明(Object declarations)

Kotlin中可以使用Object声明来定义单例,称之为对象声明(object declaration)

    object DefaultListener : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            // ...
        }

        override fun mouseEntered(e: MouseEvent) {
            // ...
        }
    }

直接使用单例名引用该对象:

    DefaultListener.mouseClicked(...)

注意:对象声明不能是局部的(也就是直接嵌套在函数中),但可以嵌套在其它对象声明或非内部类中。

友对象(Companion Objects)

在一个类中声明的对象可以使用companion关键词定义:

    class MyClass {
        companion object Factory {
            fun create(): MyClass = MyClass()
        }
    }

友对象成员直接使用类名作为限定符进行使用:

    val instance = MyClass.create()

友对象名称可以忽略:

    class MyClass {
        companion object {
        }
    }

    val x = MyClass.Companion

注意,尽管友对象的成员看上去像其它语言(例如Java)中的静态成员,但在运行时,它们是真实对象的实例成员。在与Java进行互操作中,可以使用@JvmStatic注解使其成为真正的静态方法。

对象表达式和声明的语义区别

对象表达式和声明有一个重要的语义区别:

  • 对象表达式是**立即(immediately)**执行(并且初始的)
  • 对象声明是**懒(lazily)**初始化,初始化在第一次访问时进行
  • 一个友对象在对应的类加载时进行初始化,与Java静态初始化器的语义一致