【问题标题】:How does initialisation of Scala objects work?Scala 对象的初始化如何工作?
【发布时间】:2016-01-05 18:19:34
【问题描述】:

我正在运行一个 sbt 应用程序实例化一个 MyObject 类的对象,它使用来自其伴随对象的 val。这是主要的类(对象):

object MainClass {

  def main(args: Array[String]) {
   val a = new MyObject()
  }
}

这里是MyObject的定义:

import java.text.SimpleDateFormat
import java.util.Calendar


class MyObject {
  val aValue = MyObject.yesterday
}

object MyObject {

  val yesterday = getDaysAgo(1)

  val dateNumFormat = new SimpleDateFormat("yyyymmdd")

  private def getDaysAgo(n: Int) = {
    val today = Calendar.getInstance()
    today.add(Calendar.DAY_OF_MONTH, -n)
    //println(dateNumFormat.format(today.getTime))
    today.getTime
  }
}

当我取消注释 println 语句时,我得到(确切的)以下错误:

$ sbt run
[info] Loading project definition from C:\Work\metaswitch\RandomProject\project
[info] Set current project to RandomProject (in build file:/C:/Work/metaswitch/RandomProject/)
[info] Compiling 1 Scala source to C:\Work\metaswitch\RandomProject\target\scala-2.11\classes...
[info] Running MainClass
[error] (run-main-0) java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
    at MyObject.<init>(MyObject.scala:21)
    at MainClass$.main(MainClass.scala:6)
    at MainClass.main(MainClass.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
Caused by: java.lang.NullPointerException
    at MyObject$.getDaysAgo(MyObject.scala:13)
    at MyObject$.<init>(MyObject.scala:6)
    at MyObject$.<clinit>(MyObject.scala)
    at MyObject.<init>(MyObject.scala:21)
    at MainClass$.main(MainClass.scala:6)
    at MainClass.main(MainClass.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
[trace] Stack trace suppressed: run last compile:run for the full output.
java.lang.RuntimeException: Nonzero exit code: 1
    at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last compile:run for the full output.
[error] (compile:run) Nonzero exit code: 1
[error] Total time: 2 s, completed 06-Jan-2016 11:21:16

【问题讨论】:

  • 什么是dateNumFormat?它是如何以及在哪里定义的?您能否确认堆栈跟踪中的行号与您的示例代码的行完全对应(例如第 48 行 - 您的代码中的内容是什么)?
  • 我不知道为什么取消注释println 会使这项工作,但在阅读stackoverflow.com/questions/12184997/… 之后,我玩了一下发现如果你切换定义的顺序(先对象然后类) 它工作正常。
  • “运行 sbt 应用程序”是什么意思?
  • 请注意,它是“伴随对象”,而不是“组件对象”。
  • 字段的初始化以文本顺序发生(JLS,但对于 Scala AFAIK 也是如此)。给定代码中的声明顺序,首先声明 yesterday,它将首先调用 getDaysAgo 进行初始化,这反过来将读取未初始化的 dateNumFormat 字段,该字段(此时)仍将具有其默认值null 的值。

标签: scala jvm sbt


【解决方案1】:

字段的初始化以文本顺序发生(即,按照顺序,字段在类/对象中声明)。

鉴于代码中的声明顺序,首先声明yesterday,它将首先被初始化,从而调用getDaysAgo。反过来,该方法尝试读取(尚未初始化的)字段dateNumFormat,产生null,导致表达式dateNumFormat.format(today.getTime) 抛出NullPointerException

最简单的解决方法是将dateNumFormat 的声明(和初始化)移到yesterday 之前——正如您已经发现的那样。

【讨论】:

    猜你喜欢
    • 2020-09-09
    • 2012-05-15
    • 2019-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 2018-12-07
    • 1970-01-01
    相关资源
    最近更新 更多