Kotlin - var 与对象声明之间的区别

ser*_*0ne 4 kotlin

有什么区别

object Foo : Any() { ... }
Run Code Online (Sandbox Code Playgroud)

val Foo = object : Any() { ... }
Run Code Online (Sandbox Code Playgroud)

是否存在任何语义和/或逻辑差异?何时应该使用它们?

hot*_*key 6

  • object Foo : Any() { ... }

    这是一个对象声明,它声明一个类似单例的类型Foo,其单个实例包含在object范围内声明的成员,并在第一次访问时延迟初始化。它可以在顶层或其他类型内部使用,但不能在函数体内使用。当在另一个类型中声明时,它仍然只会创建一个对象,而不是每个封闭类型的实例创建一个对象。

    class Bar {
        object Foo : Any() { ... } // only one object is created
    }
    
    Run Code Online (Sandbox Code Playgroud)

    对象声明通常用于封装全局单例状态并对相关的公共 API 成员进行分组。然而,由于Foo可以作为普通对象使用,因此还有更多用例。其中之一是声明为密封类object的子类型。

  • val Foo = object : Any() { ... }

    这是一个对象表达式,它也可以在函数体内使用。当它被评估时,它每次都会创建一个新对象。特别是,如果它在另一个类型中声明,它将为封闭类型的每个实例创建一个新对象。

    class Bar {
        val foo = object : Any() { ... } // new object for each instance of Bar
    }
    
    Run Code Online (Sandbox Code Playgroud)

    当在顶层声明时,它仍然是一个单例,但它将在第一次访问文件外观类(包含该文件的其他顶级成员)时初始化,而不是访问val.

    当您以这种方式声明属性时,您将无法调用在object属性范围内添加的成员,这与对象声明不同。但是,当用作局部变量时,这样的 aval将暴露其附加成员。

    // 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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    对属性进行此限制的目的是避免在匿名类(对象表达式编译到的对象)中使用公共 API,这些 API 可能在下次编译时以不兼容的方式隐式更改。相反,对象声明声明一个命名类型。

    对象表达式和对象声明都可以从类继承并实现接口。当您需要提供不想用类实现的接口实例时,对象表达式特别有用(例如,它是一个不会在其他任何地方使用的临时实现):

    // in a library:
    interface ResponseHandler {
        fun onSuccess(response: Response): Unit
        fun onError(exception: Exception): Unit
    }
    
    fun Request.execute(responseHandler: ResponseHandler) { ... }
    
    Run Code Online (Sandbox Code Playgroud)

    // your code:
    val request: Request = ...
    
    request.execute(object : ResponseHandler {
        fun onSuccess(response: Response) { ... } // provide the implementations
        fun onError(exception: Exception) { ... } // for these two functions
    })
    
    Run Code Online (Sandbox Code Playgroud)

注意:在这两种情况下,您都可以省略: Any(),因为这Any是对象声明和对象表达式的默认超类型。