# 對象表達式與聲明
有的時候我們需要創建對一些類的一個有細微改進的對象,而不用明確地為它聲明一個新的子類。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) 章節。
### 對象表達式和聲明間語義的差別
在對象表達式和聲明之間有一個重要的語義差別:
* 對象聲明在第一次被訪問的時候才被延遲初始化
* 對象表達式在它們被使用的地方立即執行(并初始化)。