本篇文章就是官网的教程笔记:官网地址
为什么要用对象表达式和对象声明?
有时候,我们需要创建一个对某个类做了轻微改动的类的对象,而不用为之显式声明新的子类。 Kotlin 用对象表达式 和对象声明 处理这种情况。
先来看一下对象表达式和对象声明是如何分别实现的
对象表达式 | 对象声明 |
/** * 对象表达式 */ ① var obj = object {
} ② var obj2 = object : Any() { } | /** * 对象声明 */ ③ object MyObject {
} ④ object MyObject2 : Any() {
} |
对象表达式形式(对应上面①②) ① object { } 或者 ② object :超类 { }; | 对象表声明形式(对应上面③④) ③ object 类名 { } 或者 ④ object 类名:超类 { |
总结:对象表达式object 不跟名称可放在等号右边;
对象声明object 后面跟名称不可放在等号右边
注意:在使用对象表达式的时候,匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的返回类型或者用作公有属性的类型,那么该函数或属性的实际类型会是匿名对象声明的超类型,如果你没有声明任何超类型,就会是 Any
。在匿名对象中添加的成员将无法访问。
class C {
// 私有函数,所以其返回类型是匿名对象类型
private fun foo() = object {
val x: String = "x"
}
// 公有函数,所以其返回类型是 Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // 没问题
val x2 = publicFoo().x // 错误:未能解析的引用“x”
}
}
对象表达式 | 对象声明 |
没有类名直接object{ },也叫匿名对象 | 有类名object 类名{ } |
可以放在赋值语句等号右边 | 不可放在赋值语句等号右边,因为不是表达式 |
对象表达式是在使用他们的地方立即执行(及初始化)的 | 对象声明是在第一次被访问到时延迟初始化的 |
可以继承或实现超类 | 可以继承或实现超类 |
===================================================================
伴生对象:类内部的对象声明可以用 companion 关键字标记。
class DemoClass {
companion object MyCompanionObject {
fun method(){}
}
}
调用:DemoClass.method()
=====================================
伴生对象的名称可以省略
class DemoClass {
companion object{
}
}
调用: DemoClass.companion
注意:伴生对象看起来很像静态类但是运行起来仍是真实对象的实例成员,例如 :可以实现接口
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
val f: Factory<MyClass> = MyClass
注意:伴生对象的初始化是在相应的类被加载(解析)时,与 Java 静态初始化器的语义相匹配。