抽象超类 scala 中的断言创建 NPE [英] Assertions in abstract superclass scala creating NPE

查看:23
本文介绍了抽象超类 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?

类似问题:

代码契约:抽象类中的不变量

Scala 抽象类中的私有构造函数?

以及在线评论:https://gist.github.com/jkpl/4932e8730c19d81010>

and also online commentary: https://gist.github.com/jkpl/4932e8730c1810261381851b13dfd29d

推荐答案

当你声明一个 val 时,会发生几种情况:

When you declare a val, several things happen:

  1. 编译器确保在初始化类的实例时为变量分配足够的空间
  2. 创建了一个访问器方法
  3. 创建用于设置变量初始值的初始化程序.

您的代码

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()

因此,发生以下情况:

  1. aSet_AaSet_B 的内存被分配并设置为 null.
  2. A 的初始化程序已运行.
  3. require on aSet.contains(3) 被调用
  4. 由于 aSetB 中被覆盖,它返回 aSet_B.
  5. 由于 aSet_Bnull,因此抛出 NPE.
  1. Memory for aSet_A and aSet_B is allocated and set to null.
  2. Initializer of A is run.
  3. require on aSet.contains(3) is invoked
  4. Since aSet is overridden in B, it returns aSet_B.
  5. Since aSet_B is null, 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()

这会抛出 requirement failed 异常:

java.lang.IllegalArgumentException: requirement failed

<小时>

Scala 常见问题解答的强制性链接:


Obligatory link to Scala's FAQ:

相关问题列表:

  1. 为什么使用val实现抽象方法并从val表达式中的超类调用返回NullPointerException
  2. 覆盖值父代码已运行但未在父代码处分配值

这篇关于抽象超类 scala 中的断言创建 NPE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆