首页 > 解决方案 > Kotlin - var 与对象声明之间的区别

问题描述

和有什么区别

object Foo : Any() { ... }

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

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

标签: kotlin

解决方案


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

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

    class Bar {
        object Foo : Any() { ... } // only one object is created
    }
    

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

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

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

    class Bar {
        val foo = object : Any() { ... } // new object for each instance of Bar
    }
    

    当在顶层声明时,它仍然是一个单例,但它会在第一次访问文件外观类(包含该文件的其他顶层成员)而不是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
    }
    

    对属性进行此限制的目的是避免在匿名类(对象表达式被编译到)中使用公共 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它是对象声明和对象表达式的默认超类型。


推荐阅读