在Scala工作表中使用自定义枚举时,我收到一个错误:java.lang.ExceptionInInitializeError

在Scala工作表中使用自定义枚举时,我收到一个错误:java.lang.ExceptionInInitializeError,scala,enums,scala-ide,Scala,Enums,Scala Ide,更新-2014/9/17 事实证明,如果将println(Value.Player2)作为第一个命令,则先前更新(从2013年2月19日起)中的解决方案也无法运行;i、 e.序号仍然分配不正确 从那以后,我创造了一个新的世界。实现等待分配序号,直到所有JVM类/对象初始化完成。它还有助于用额外的数据扩展/修饰每个枚举成员,同时对于(反)序列化仍然非常有效 我还创建了一个详细介绍Scala中使用的所有不同枚举模式的示例(包括我在上面提到的要点中的解决方案) 我正在使用的是新安装的(预安装了Sca

更新-2014/9/17

事实证明,如果将
println(Value.Player2)
作为第一个命令,则先前更新(从2013年2月19日起)中的解决方案也无法运行;i、 e.序号仍然分配不正确

从那以后,我创造了一个新的世界。实现等待分配序号,直到所有JVM类/对象初始化完成。它还有助于用额外的数据扩展/修饰每个枚举成员,同时对于(反)序列化仍然非常有效

我还创建了一个详细介绍Scala中使用的所有不同枚举模式的示例(包括我在上面提到的要点中的解决方案)


我正在使用的是新安装的(预安装了ScalaIDE的Eclipse)。我使用的是Windows7-64位。我在使用Scala工作表时取得了多种成功。在不到一个小时的时间里,我的机器已经死机三次(完全复位或一次死机)。因此,这可能是Scala工作表中的一个bug。我还不确定,也没有时间追查这个问题。然而,这个枚举问题正在阻止我进行测试

我在Scala工作表中使用以下代码:

package test

import com.stack_overflow.Enum

object WsTempA {
  object Value extends Enum {
    sealed abstract class Val extends EnumVal
    case object Empty   extends Val; Empty()
    case object Player1 extends Val; Player1()
    case object Player2 extends Val; Player2()
  }

  println(Value.values)
  println(Value.Empty)
}
以上方法很好。但是,如果注释掉第一个println,第二行将抛出一个异常:java.lang.ExceptionInInitializerError。我只是一个Scala新手,不明白为什么会发生这种情况。任何帮助都将不胜感激

下面是Scala工作表右侧的堆栈跟踪(左侧已剥离,以便在此处显示):

java.lang.ExceptionInInitializeError
在test.WsTempA$Value$Val处(test.WsTempA.scala:7)
test.WsTempA$Value$Empty$(test.WsTempA.scala:8)
test.WsTempA$Value$Empty$。(test.WsTempA.scala)
在test.WsTempA$$anonfun$main$1.apply$mcV$sp(test.WsTempA.scala:14)
位于org.scalaide.worksheet.runtime.library.WorksheetSupport$$anonfun$$exe
可爱$1.应用$mcV$sp(工作表支持。scala:76)
在org.scalaide.worksheet.runtime.library.WorksheetSupport$重定向(W
工作表支持。scala:65)
在org.scalaide.worksheet.runtime.library.WorksheetSupport$.$execute(Wor
ksheetSupport.scala:75)
在test.WsTempA$.main处(test.WsTempA.scala:11)
在test.WsTempA.main(test.WsTempA.scala)处
原因:java.lang.NullPointerException
test.WsTempA$Value$(test.WsTempA.scala:8)
test.WsTempA$Value$(test.WsTempA.scala)
... 9更多
com.stack_overflow.Enum类来自。为了简单起见,我在这里粘贴了我的版本(以防在复制/粘贴操作中遗漏了一些关键内容):

package com.stack\u溢出
//抄袭https://stackoverflow.com/a/8620085/501113
抽象类枚举{
输入Val(Val)
valuesByName_u+=(toString->theVal)
}
}
}
任何形式的指导都将不胜感激


更新-2013/2/19

在使用Rex Kerr进行了几次循环后,下面是代码的更新版本:

package test

import com.stack_overflow.Enum

object WsTempA {
  object Value extends Enum {
    sealed abstract class Val extends EnumVal
    case object Empty   extends Val {Empty.init}   // <---changed from ...Val; Empty()
    case object Player1 extends Val {Player1.init} // <---changed from ...Val; Player1()
    case object Player2 extends Val {Player2.init} // <---changed from ...Val; Player2()
    private val init: List[Value.Val] = List(Empty, Player1, Player2) // <---added
  }

  println(Value.values)
  println(Value.Empty)
  println(Value.values)
  println(Value.Player1)
  println(Value.values)
  println(Value.Player2)
  println(Value.values)
包测试
导入com.stack_overflow.Enum
对象WsTempA{
对象值扩展枚举{
密封抽象类Val扩展了EnumVal

case object Empty扩展Val{Empty.init}/这里有两个问题:一个是由于初始化问题导致代码无法工作,另一个是IDE问题。我将只讨论代码失败

问题是在实际访问
Empty
之前需要运行
Empty()
,但是访问内部大小写对象不会在外部对象上运行初始值设定项,因为它们只是假装是内部对象的成员。(在
中没有包含
Empty
的变量)

通过运行
apply()
方法作为
Empty
的初始值设定项的一部分,可以绕过此问题:

object Value extends Enum {
  sealed abstract class Val extends EnumVal
  case object Empty   extends Val { apply() }
  case object Player1 extends Val { apply() }
  case object Player2 extends Val { apply() }
}
现在您的初始化错误应该消失了。(因为您必须这样做,我建议
apply()
实际上是一个错误的名称选择;也许
set
或类似的名称会更好(更短)

如果将
println
粘贴到
main
方法中,下面是字节码在打印
值时的样子。值

public void main(java.lang.String[]);
  Code:
   0:   getstatic   #19; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   3:   getstatic   #24; //Field WsTempA$Value$.MODULE$:LWsTempA$Value$;
   6:   invokevirtual   #30; //Method Enum.values:()Lscala/collection/immutable/List;
   9:   invokevirtual   #34; //Method scala/Predef$.println:(Ljava/lang/Object;)V
   12:  return
注意第3行,在这里您得到了
本身的一个静态字段(这意味着JVM确保该字段已初始化)

public void main(java.lang.String[]);
  Code:
   0:   getstatic   #19; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   3:   getstatic   #24; //Field WsTempA$Value$Empty$.MODULE$:LWsTempA$Value$Empty$;
   6:   invokevirtual   #28; //Method scala/Predef$.println:(Ljava/lang/Object;)V
   9:   return
现在,第3行不是指
值,而是指内部对象,这意味着首先调用内部对象的初始值设定项,然后调用外部对象的初始值设定项,然后它看到内部对象的初始值设定项应该完成(但实际上没有完成)…并对其调用一个方法,然后…boom


如果将
apply
放在
Empty
初始值设定项中,则会保存该初始值设定项,因为
初始值设定项即使被无序调用,也不再调用
Empty
上的方法。因此它奇迹般地工作了。(请确保不引入任何其他方法调用!)

您能发布完整的堆栈跟踪吗?:)(如果您无法从UI获取,请在workspace/.metadata/.log中查看)@briTransmisth Tyvm请求。我在上面添加了堆栈跟踪。但是,它在Scala工作表中被截断(缺少9行)。如果您需要我深入查看您提到的日志,我会这样做。我现在已经深入查看了日志,但没有出现此错误。还有一个异常似乎完全不相关。如果您仍然希望我深入查看,请告诉我。无需调用
Empty.init
--只需
init
即可。此外,我注意到总的来说,his对于Enum来说是一个非常不合适的解决方案,因为您必须将每个项列出两次,并且有大约35个bo字符
object Value extends Enum {
  sealed abstract class Val extends EnumVal
  case object Empty   extends Val { apply() }
  case object Player1 extends Val { apply() }
  case object Player2 extends Val { apply() }
}
public void main(java.lang.String[]);
  Code:
   0:   getstatic   #19; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   3:   getstatic   #24; //Field WsTempA$Value$.MODULE$:LWsTempA$Value$;
   6:   invokevirtual   #30; //Method Enum.values:()Lscala/collection/immutable/List;
   9:   invokevirtual   #34; //Method scala/Predef$.println:(Ljava/lang/Object;)V
   12:  return
public void main(java.lang.String[]);
  Code:
   0:   getstatic   #19; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   3:   getstatic   #24; //Field WsTempA$Value$Empty$.MODULE$:LWsTempA$Value$Empty$;
   6:   invokevirtual   #28; //Method scala/Predef$.println:(Ljava/lang/Object;)V
   9:   return