抽象超类Scala中的断言创建NPE [英] Assertions in abstract superclass scala creating NPE
本文介绍了抽象超类Scala中的断言创建NPE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
在REPL中输入以下代码
The following code, when entered in REPL
abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }
class B extends A { val aSet = Set(4,5,6) }
new B()
给出空值异常,而不是不变的失败。
gives a null point exception, rather than an invariant failure.
解决这个问题的最佳习惯是什么?
What would be the best idiom to solve this problem?
类似的问题:
以及在线评论: https://gist.github.com/jkpl/4932e8730c1810261381851b13dfd29d
推荐答案
当您声明 val
,会发生几件事:
When you declare a val
, several things happen:
- Th e编译器确保在初始化类的实例时为变量分配足够的空间
- 创建访问器方法
- 设置变量的初始值。
您的代码
abstract class A { val aSet: Set[Int]; require(aSet.contains(3)) }
class B extends A { val aSet = Set(4,5,6) }
new B()
大致等于
abstract class A {
private var aSet_A: Set[Int] = null
def aSet: Set[Int] = aSet_A
require(aSet.contains(3))
}
class B extends A {
private var aSet_B: Set[Int] = Set(4,5,6)
override def aSet: Set[Int] = aSet_B
}
new B()
因此,发生以下情况:
- 分配了
aSet_A
和aSet_B
的内存并设置为null
。 - 运行
A
的初始化程序。 -
require
在aSet.contains(3)
上 - 由于
aSet
在B
中被覆盖,因此它返回aSet_B
。 - 由于
aSet_B
为null
(NPE)
- Memory for
aSet_A
andaSet_B
is allocated and set tonull
. - Initializer of
A
is run. require
onaSet.contains(3)
is invoked- Since
aSet
is overridden inB
, it returnsaSet_B
. - Since
aSet_B
isnull
, an NPE is thrown.
到避免这种情况,您可以将 aSet
实现为惰性变量:
To avoid this, you can implement aSet
as a lazy variable:
abstract class A {
def aSet: Set[Int]
require(aSet.contains(3))
}
class B extends A {
lazy val aSet = Set(4,5,6)
}
new B()
这将引发要求失败
例外:
java.lang.IllegalArgumentException: requirement failed
强制性链接到Scala的常见问题解答:
Obligatory link to Scala's FAQ:
- Why is my abstract or overridden val null?
相关列表问题:
- Why does implement abstract method using val and call from superclass in val expression return NullPointerException
- Overridden value parent code is run but value is not assigned at parent
这篇关于抽象超类Scala中的断言创建NPE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文