💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 对象表达式与声明 有的时候我们需要创建对一些类的一个有细微改进的对象,而不用明确地为它声明一个新的子类。Java 把这种情况称为*匿名类*。Kotlin 用*对象表达式*和*对象声明*略微地扩展了这个概念。 ## 对象表达式 要创建一个从一些类型继承的匿名类的对象,我们这样写: ``` kotlin window.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { // ... } override fun mouseEntered(e: MouseEvent) { // ... } }) ``` 如果一个超类有一个构造器,必须传递给它适当的构造器参数。一些超类也许会在冒号后面指定一组由逗号分隔的列表: ``` kotlin open class A(x: Int) { public open val y: Int = x } interface B {...} val ab = object : A(1), B { override val y = 15 } ``` 如果有可能,我们需要“只是一个对象”,不要超类,我们可以简单地说: ``` kotlin val adHoc = object { var x: Int = 0 var y: Int = 0 } print(adHoc.x + adHoc.y) ``` 非常类似于 Java 的匿名内部类,对象里的代码表达式可以访问封闭的作用域的变量(不像 Java,这不会限制为 final 变量) ``` kotlin 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++ } }) // ... } ``` ## 对象声明 [单例](http://en.wikipedia.org/wiki/Singleton_pattern) 是一种非常有用的模式,并且 Kotlin(Scala 以后)让它容易的声明单例: ``` kotlin object DataProviderManager { fun registerDataProvider(provider: DataProvider) { // ... } val allDataProviders: Collection<DataProvider> get() = // ... } ``` 这被称为*对象声明*。如果有一个名称跟在 `object` 关键字后面,我们就不再是描述一个_表达式_了。我们不能把这样的东西赋值给一个变量,但我们可以通过它的名称引用它。这样的对象可以有超类: ``` kotlin object DefaultListener : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { // ... } override fun mouseEntered(e: MouseEvent) { // ... } } ``` **注意**:对象声明不能是局部的(意即被直接嵌套在一个函数中),但它们可以被嵌套在其它对象声明或是非内部类里面。 ### 友元对象 一个类内部的对象声明可以用 `companion` 关键字标记: ``` kotlin class MyClass { companion object Factory { fun create(): MyClass = MyClass() } } ``` 友元对象的成员可以通过使用简单地类名限定符调用: ``` kotlin val instance = MyClass.create() ``` 使用名称 `Companion` 的情况下,友元对象的名称可以是隐含的: ``` kotlin class MyClass { companion object { } } val x = MyClass.Companion ``` 注意,即使友元对象的成员在其它语言里面看上去像是静态成员,在运行时仍然是实际对象的实例成员,并且可以实现接口。例如: ``` kotlin interface Factory<T> { fun create(): T } class MyClass { companion object : Factory<MyClass> { override fun create(): MyClass = MyClass() } } ``` 然而,在 JVM 上你可以有实际生成为静态的方法和字段的友元对象成员,如果你使用 `@JvmStatic` 注解。更详细的信息查看 [Java 互用性](java-interop.html#static-methods-and-fields) 章节。 ### 对象表达式和声明间语义的差别 在对象表达式和声明之间有一个重要的语义差别: * 对象声明在第一次被访问的时候才被延迟初始化 * 对象表达式在它们被使用的地方立即执行(并初始化)。