当子类使用val实现它时,超类中的Scala抽象方法为null?
Posted
技术标签:
【中文标题】当子类使用val实现它时,超类中的Scala抽象方法为null?【英文标题】:Scala abstract method is null in superclass when subclass implements it using val? 【发布时间】:2010-07-28 13:13:14 【问题描述】:我在我的 scala 代码中发现了一个错误,这让我很困惑。以下是问题的简化版本。
在抽象类的构造函数中,我想检查一些关于抽象方法的断言。 因此,当创建子类的对象时,会检查这些断言,以查看是否所有都按应有的方式实现。
但是,当子类使用“val”实现抽象方法时会出错:
Scala 代码:
abstract class A
def aval : String
assert(aval != null, "aval == null")
assert(aval == "B", "aval: "+aval)
class B extends A
def aval = "B"
class C extends A
val aval = "B"
object VariousScalaTests
def main(args : Array[String]) : Unit =
val b = new B
val c = new C
Scala 错误:
Exception in thread "main" java.lang.AssertionError: assertion failed: aval == null
at scala.Predef$.assert(Predef.scala:92)
at A.<init>(VariousScalaTests.scala:4)
at C.<init>(VariousScalaTests.scala:12)
at VariousScalaTests$.main(VariousScalaTests.scala:19)
at VariousScalaTests.main(VariousScalaTests.scala)
所以它在最后一行代码失败:“val c = new C”。 B 类完美运行,但 C 类不行!唯一的区别是C使用“val”实现aval,B使用“def”实现。
所以我的问题是,最重要的是,为什么会有这种差异?我不明白发生了什么。
有没有办法让它在 scala 的两种情况下都能按我的意愿工作?还是我只是错过了一种更优雅的方式来在 scala 中断言我想要的东西?
【问题讨论】:
【参考方案1】:在 Scala 中,您可以使用早期定义功能在调用超级构造函数之前初始化子类的 val:
class C extends
val aval = "B"
with A
【讨论】:
不确定。在 scala lang 规范第 5.1.6 节中,它被称为“早期定义”。【参考方案2】:这个等效的 Java 代码应该可以解释问题:
public abstract class A
public String aval();
public class B extends A
public String aval()
return "B";
public class C extends A
private String _aval;
public C()
_aval = "B";
public String aval()
return _aval;
当你跑步时
val c = new C
A
的构造函数运行在C
的构造函数之前,_aval
字段尚未分配。所以aval()
方法返回null
(_aval
字段的初始值)。但是在
val b = new B
不存在这样的问题。
一般情况下,you should try to avoid calling virtual methods from a constructor.
有没有办法让它在 scala 的两种情况下都按我的意愿工作?
有关一些方法,请参阅this question。
【讨论】:
你的java代码解释得很好!我现在明白了......考虑到这样的行为,“避免从构造函数调用虚拟方法”似乎是非常好的建议。当然在 scala 中,就像在 java 代码中一样,它更清楚发生了什么。在我的特定情况下,我将寻找另一种优雅地检查子类的方法,您的链接可能会有所帮助。至少这个错误的奥秘现在已经消失了;-)以上是关于当子类使用val实现它时,超类中的Scala抽象方法为null?的主要内容,如果未能解决你的问题,请参考以下文章