为何在类外部引用伴生对象内的对象需加Companion.前缀?
Kotlin伴生对象嵌套成员访问行为解析
一、伴生对象内命名object的访问限制
Kotlin的伴生对象本质是类的一个特殊嵌套对象实例,默认名称为Companion。通常我们可以省略Companion直接访问伴生对象的成员属性、函数,这是Kotlin提供的语法糖。
但对于在伴生对象内部定义的嵌套命名对象(如以下代码中的object Obj),它属于伴生对象的嵌套类型,而非伴生对象的直接成员。Kotlin的语法糖不会将这类嵌套类型提升到外部类的级别,因此必须通过Companion前缀来访问这个嵌套对象,否则编译器无法解析引用。
示例代码:
class Cls { companion object { object Obj { val attr = 1 } } } fun main() { println(Cls.Obj.attr) // 错误:Unresolved reference: Obj —— 嵌套命名对象不属于外部类的直接成员 println(Cls.Companion.Obj.attr) // 正常 —— 通过伴生对象实例访问其内部嵌套对象 println(Cls.Obj) // 错误:Unresolved reference: Obj println(Cls.Companion.Obj) // 正常 }
二、伴生对象内匿名对象的成员访问限制
当用val Obj = object { ... }的方式定义时,Obj是伴生对象的一个成员属性,因此可以通过Cls.Obj或Cls.Companion.Obj直接访问(符合伴生对象成员的语法糖规则)。
但这里的Obj是匿名对象,其成员(比如attr)仅在定义它的作用域(即伴生对象内部)可见。在外部作用域(如main函数),Obj的静态类型会被编译器推断为Any(如果没有指定显式超类型),因此编译器无法识别attr属性,导致访问报错。
示例代码:
class Cls { companion object { val Obj = object { val attr = 1 } } } fun main() { println(Cls.Obj.attr) // 错误:Unresolved reference: attr —— 外部无法识别匿名对象的成员 println(Cls.Companion.Obj.attr) // 错误:Unresolved reference: attr —— 同样受匿名对象的作用域限制 println(Cls.Obj) // 正常 —— 可以访问伴生对象的成员属性本身 println(Cls.Companion.Obj) // 正常 }
如果需要在外部访问匿名对象的成员,你可以给匿名对象指定一个显式的超类型(比如定义一个包含attr属性的接口),示例如下:
interface HasAttr { val attr: Int } class Cls { companion object { val Obj = object : HasAttr { override val attr = 1 } } } fun main() { println(Cls.Obj.attr) // 正常 —— 此时Obj的静态类型是HasAttr,编译器能识别attr属性 }
内容的提问来源于stack exchange,提问作者Ryan Haining
相关产品推荐
相关产品推荐

