抽象类与抽象变量和子构造函数;斯卡拉

时间:2015-03-26 13:56:04

标签: scala inheritance abstract-class

我有一个抽象类,由另一个类扩展。

object StackOverflowTest extends App
{
  new ChildFunction()
}

abstract class Function() {
  val a: Double
  val b: Double

  println(a, b)
}

class ChildFunction() extends Function() {
  val a = 0.02
  val b = 0.2
}

当我实例化ChildFunction时,会为0.0a打印b

这显然不是我想要的行为,甚至是预期的行为。

我找到解决此问题的唯一方法是在ChildFunction lazy val a = 0.02中说明。 这是正确的解决方案吗?

1 个答案:

答案 0 :(得分:4)

使val延迟工作,因为它移动0.02写入字段的点。要了解发生的情况,请阅读以下代码,这是scalac为您的示例生成的java字节代码。

要注意的是,字段a和b存储在子对象上,并且直到调用父对象的构造函数之后才会写入它们的值0.02和0.2。但是,在写入字段之前,将在父项的构造函数中调用println。因此你的问题。

使vals延迟工作,因为在调用a()或b()时,将调用初始化代码..这就是父类现在将在子类上调用代码来设置儿童班。

public abstract class Function implements scala.ScalaObject {
  public abstract double a();

  public abstract double b();

  public Function();   // NB: calls a() and b() on the child class
    Code:
       0: aload_0       
       1: invokespecial #13                 // Method java/lang/Object."<init>":()V
       4: getstatic     #19                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       7: new           #21                 // class scala/Tuple2$mcDD$sp
      10: dup           
      11: aload_0       
      12: invokevirtual #25                 // Method a:()D
      15: aload_0       
      16: invokevirtual #27                 // Method b:()D
      19: invokespecial #30                 // Method scala/Tuple2$mcDD$sp."<init>":(DD)V
      22: invokevirtual #34                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
      25: return        
}



public class ChildFunction extends Function implements scala.ScalaObject {
  public double a();
    Code:
       0: aload_0       
       1: getfield      #12                 // Field a:D
       4: dreturn       

  public double b();
    Code:
       0: aload_0       
       1: getfield      #14                 // Field b:D
       4: dreturn       

  public ChildFunction();    // NB invokes parent constructor BEFORE writing values to fields a and b.
    Code:
       0: aload_0       
       1: invokespecial #20                 // Method Function."<init>":()V
       4: aload_0       
       5: ldc2_w        #21                 // double 0.02d
       8: putfield      #12                 // Field a:D
      11: aload_0       
      12: ldc2_w        #23                 // double 0.2d
      15: putfield      #14                 // Field b:D
      18: return        
}

你可以修复&#39;这个问题通过使用defs而不是lazy val(下面的例子)。或者更好的是,删除println并仅在完全构造ChildFunction之后调用a()和b()

object StackOverflowTest extends App
{
  new ChildFunction()
}

abstract class Function() {
  def a: Double
  def b: Double

  println(a, b)
}

class ChildFunction() extends Function() {
  override def a = 0.02
  override def b = 0.2
}