You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 18:33:31