当子类使用val实现它时,Scala抽象方法在超类中为null?

Cod*_* 23 5 inheritance constructor scala

我在我的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
    }
}
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

所以它在最后一行代码中失败了:"val c = new C".B级工作得很好,但C级没有!唯一的区别是C使用"val"实现aval,使用"def"实现B.

所以我的问题,最重要的是,为什么会出现这种差异?我不明白发生了什么.

有没有办法让它在scala中的两种情况下都能正常工作?或者我只是错过了一种更优雅的方式来断言我想要的scala?

ven*_*hka 6

在Scala中,您可以使用早期定义功能在调用超级构造函数之前初始化子类的val:

class C extends {
  val aval = "B"
} with A
Run Code Online (Sandbox Code Playgroud)


Ale*_*nov 5

这个等效的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

当你跑步

val c = new C
Run Code Online (Sandbox Code Playgroud)

构造函数之前A运行构造函数和尚未分配的字段.因此该方法返回(字段的初始值).但在C_avalaval()null_aval

val b = new B
Run Code Online (Sandbox Code Playgroud)

没有这样的问题.

通常,您应该尽量避免从构造函数中调用虚方法.

有没有办法让它在scala中的两种情况下都能正常工作?

有些方法,请参阅此问题.