有的时候没有明确的指定一个类的父类而我们需要创建一个类来轻微的修改一些类。java的处理这种情况的方式是创建一个匿名的内部类,而kotlin用object表达式和object声明来实现。
Object expressions
为了创建一个继承自其它类的匿名类,我们这样写:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// …
}
override fun mouseEntered(e: MouseEvent) {
// …
}
})
如果父类有构造器,那么也需要将构造 器参数传过去。如果有多个父类那就必须在冒号之后用逗号分隔开:
open class A(x: Int) {
public open val y: Int = x
}
interface B {…}
val ab = object : A(1), B {
override val y = 15
}
随便一说,如果我们只是需要一个object,没有父类,我可以这么写:
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
就像java的匿名内部类一样,object表达式可以访问外部变量,但是不同于java的是,kotlin不受限于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 声明
单例模式是一个非常有用的模式,kotlin能让你更方便地定义单例模式。
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// …
}
val allDataProviders: Collection<DataProvider>
get() = // …
}
这就叫做object的声明,object关键字后面就是类的名字,我们不能再说这个是object的表达式,我们不能将这个东西指定为变量,但我们可以用它来创建一个引用。它也可以继承一个类:
object DefaultListener : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// …
}
override fun mouseEntered(e: MouseEvent) {
// …
}
}
object 声明不能在fun里面嵌套,但是可以在object声明中嵌套object声明或者在非内部类里面嵌套
Companion Object
在一个类里面一个object声明可以用companion标记:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
companion object的成员可以被外部类访问,如下:
val instance = MyClass.create()
companion object 的名字可以忽略,在这种情况下Companion可以用:
class MyClass {
companion object {
}
}
val x = MyClass.Companion
注意,在其它语言看来companion object 的成员看起来很像静态成员,在运行时这些成员实例,比如实例一个接口:
interface Factory {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
然而,如果你使用注解@JvmStatic在JVM会把companion object 的成员生成静态类型,可以看到更多细节。
object声明和object表达式语义不同的地方
- object 声明是懒加载,也是第一次使用的时候才初始化
- object表达式是立刻执行的