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

时间:2019-08-28 22:25:02

标签: kotlin

两者之间有什么区别

object Foo : Any() { ... }

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

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

1 个答案:

答案 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是对象声明和对象表达式的默认超类型。