两者之间有什么区别
object Foo : Any() { ... }
和
val Foo = object : Any() { ... }
语义和/或逻辑上是否存在差异,何时应使用它们?
答案 0 :(得分:4)
object Foo : Any() { ... }
这是一个object declaration,它声明一个类似单例的类型Foo
,其单个实例包含在object
范围内声明的成员,并在首次访问时被延迟初始化。它可以在顶层或其他类型中使用,但不能在功能体内使用。在另一种类型内声明时,它仍将仅创建一个对象,而不为每个封闭类型实例创建一个对象。
class Bar {
object Foo : Any() { ... } // only one object is created
}
对象声明通常用于封装全局单例状态并将相关的公共API成员分组。但是,由于Foo
可以用作普通对象,因此存在更多用例。其中之一是将object
声明作为sealed class的子类型。
val Foo = object : Any() { ... }
这是一个object expression,它也可以在函数体内使用。评估后,每次都会创建一个新对象。特别是,如果在另一个类型中声明了它,它将为每个封闭类型的实例创建一个新对象。
class Bar {
val foo = object : Any() { ... } // new object for each instance of Bar
}
在顶层声明时,它仍然是单例,但是它将在首次访问文件外观类(包含该文件的其他顶级成员)而不是访问val
时初始化。
以这种方式声明属性时,与对象声明相反,您将无法调用在属性的object
范围内添加的成员。但是,当val
用作局部变量时,将公开其其他成员。
// on top level:
val foo = object : Any() {
val x = 1
}
fun main() {
println(foo.x) // error, unresolved reference 'x'
val bar = object : Any() {
val x = 1
}
println(bar.x) // OK
}
此属性限制的目的是避免在匿名类(对象表达式被编译到)中使用公共API,该匿名类在下一次编译时可能会以不兼容的方式隐式更改。相反,对象声明声明了命名类型。
对象表达式和对象声明都可以从类继承并实现接口。当您需要提供不想用类实现的接口实例时(例如,它是一个临时实现,将不会在其他地方使用),对象表达式特别有用:
// in a library:
interface ResponseHandler {
fun onSuccess(response: Response): Unit
fun onError(exception: Exception): Unit
}
fun Request.execute(responseHandler: ResponseHandler) { ... }
// your code:
val request: Request = ...
request.execute(object : ResponseHandler {
fun onSuccess(response: Response) { ... } // provide the implementations
fun onError(exception: Exception) { ... } // for these two functions
})
注意:在两种情况下,都可以省略: Any()
,因为Any
是对象声明和对象表达式的默认超类型。