Scala跨类访问已赋值成员变量返回null问题求解
问题根因
出现多个null输出的核心原因有两点:
globalText是A类的实例成员,每一个A类、B类的实例都持有独立的globalText属性,互相不影响。sum()方法里仅给当前调用方法的a实例的globalText赋值,后续在sum()里新建的B实例,自己的globalText从来没有被赋值过,默认就是null。- 类的构造代码(类作用域里直接写的
println、变量初始化逻辑)会在实例new出来的时候立刻执行,早于sum()方法的调用:第一次new A()的时候还没执行赋值,打印null;new B()的时候B实例自己的globalText也没被赋值,两次打印都是null。
题目存在两个硬约束:Program单例里只能实例化一次A,不能额外new其他类;sum()是第三方代码完全不能修改,因此实例成员的方案走不通,必须用全局共享的静态属性存值。
可行解决方案
利用Scala的伴生对象特性,把globalText放到A的伴生对象里作为全局共享的静态属性,所有A、B实例访问的都是同一个值,不需要修改sum()方法逻辑,也不需要在Program里额外实例化其他类。
修改后的完整代码如下:
// A的伴生对象,存全局共享的globalText object A { var globalText: String = _ } class A{ // 定义同名的getter/setter,指向伴生对象的共享属性,和原有实例成员的调用写法完全兼容 def globalText: String = A.globalText def globalText_=(value: String): Unit = { A.globalText = value } def sum(): Int = { val localText: String = "Hello World" // 此处赋值逻辑完全和原代码一致,不需要修改第三方sum方法 globalText = localText println(globalText) val b = new B() 3+4 } // 类构造阶段的打印逻辑保持不变 println(globalText) } class B extends A{ // 访问的globalText是伴生对象的共享值,sum执行过赋值后就能拿到正确结果 var globalBText = globalText println(globalBText) } object Program { def main(args: Array[String]): Unit = { // 仅实例化一次A,符合约束 val a = new A() println(a.sum()) } }
执行效果说明
代码运行后的输出顺序为:
null Hello World Hello World Hello World 7
- 第一个null是第一次new A()时,还没调用sum()给共享变量赋值,构造阶段打印的初始值,属于正常逻辑。
- 第一个Hello World是sum()方法内给共享变量赋值后打印的正确值。
- 后续两个Hello World是sum()内new B()时,B实例构造阶段访问已经赋值完成的共享变量打印的正确值,解决了之前取到null的问题。
- 最后打印sum()的返回值7,完全符合原有逻辑。
内容的提问来源于stack exchange,提问作者ProSyth
相关产品推荐
相关产品推荐

