Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala:继承中的构造函数顺序_Scala - Fatal编程技术网

Scala:继承中的构造函数顺序

Scala:继承中的构造函数顺序,scala,Scala,有人能详细解释一下scala继承中调用构造函数的顺序吗?假设我有: abstract class A { private var data: T = compute() protected def compute(): T } class ImpA extends A { var a = 0 override def compute() { a = 1 null.asInstanceOf[T] // doesn't matter } }

有人能详细解释一下scala继承中调用构造函数的顺序吗?假设我有:

abstract class A {
   private var data: T = compute()
   protected def compute(): T
}

class ImpA extends A {
   var a = 0
   override def compute() {
      a = 1
      null.asInstanceOf[T] // doesn't matter
   }
}

val inst = new ImpA
然后看起来
inst.a==0
,所以我猜当调用
ImpA
的构造函数时,也会调用
a
构造函数,这实际上触发了
compute()
,应该设置
a=1
。但是scala回到
ImpA
的构造函数并重置
a=0
。是这样吗

是否有一些众所周知的模式可以正确避免这种情况?(我并不是真的试图解决这个容易处理的问题,尽管如果有建议的模式,我很想了解它们;但我更想深入了解正在发生的事情,并希望知道为什么重新初始化变量
a
会对这种情况感兴趣。以及会发生什么情况。)如果它是一个
val
,它将导致为相同的变量分配多个引用(如果保留逻辑…)

提前谢谢

编辑:有趣的是,当您只需更改
ImpA.a
并使用引用而不是
var

class ImpA extends A {
   class B {
     var b = 0
   }
   val b = new B
   override def compute() {
      b.b += 1
      null.asInstanceOf[T] // doesn't matter
   }
}
然后它抛出一个
java.lang.NullPointerException
,因为
b
尚未实例化。以下是Yuval Itzchakov解决方案的编译内容:

  abstract class A extends Object {
      private[this] var data: Object = _;
      <accessor> private def data(): Object = A.this.data;
      <accessor> private def data_=(x$1: Object): Unit = A.this.data = x$1;
      protected def compute(): Object;
      def <init>(): test.A = {
        A.super.<init>();
        A.this.data = A.this.compute();
        ()
      }
    };
    class ImpA extends test.A {
      private[this] val b: test.ImpA$B = _;
      <stable> <accessor> def b(): test.ImpA$B = ImpA.this.b;
      override def compute(): Unit = {
        ImpA.this.b().b_=(ImpA.this.b().b().+(1));
        {
          (null: Object);
          ()
        }
      };
      override <bridge> <artifact> def compute(): Object = {
        ImpA.this.compute();
        scala.runtime.BoxedUnit.UNIT
      };
      def <init>(): test.ImpA = {
        ImpA.super.<init>();
        ImpA.this.b = new test.ImpA$B(ImpA.this);
        ()
      }
    };
    class ImpA$B extends Object {
      private[this] var b: Int = _;
      <accessor> def b(): Int = ImpA$B.this.b;
      <accessor> def b_=(x$1: Int): Unit = ImpA$B.this.b = x$1;
      <synthetic> <paramaccessor> <artifact> protected val $outer: test.ImpA = _;
      <synthetic> <stable> <artifact> def $outer(): test.ImpA = ImpA$B.this.$outer;
      def <init>($outer: test.ImpA): test.ImpA$B = {
        if ($outer.eq(null))
          throw null
        else
          ImpA$B.this.$outer = $outer;
        ImpA$B.super.<init>();
        ImpA$B.this.b = 0;
        ()
      }
    }

让我们看看编译器在编译时生成了什么(使用
-Xprint:jvm
标志):

它调用
A.super
,这是
对象
,然后调用
A.this.compute()
。此方法初始化
a
以保持值1。初始化完成后,
ImplA
a
设置为
0
,就像您在构造函数初始化期间告诉它的那样。这就是为什么您看到
a
的值
0

综上所述,执行流程如下:

  • ImplA
    调用
    A
    s init方法
  • A
    调用
    compute
    ,在
    ImplA
  • ImplA.compute
    分配
    a
    1
  • ImplA
    分配
    a
    0

  • 有关更多信息,请参见编辑:没关系,我太笨了,不会读书<代码>计算()不会在任何地方调用。您刚刚定义了它。@stefanfisher
    compute
    s构造函数中调用。谢谢,我甚至没有想到使用
    -Xprint:jvm
    标志!我将看到我的编辑会发生什么,然后自己理解NPE!=)@谢谢!这确实有助于理解。我还发现,将其设置为
    lazy val
    (但需要将
    var a
    放入绑定类)也可以正常工作(请参见我对问题的编辑)。
    class ImpA extends test.A {
      @volatile private[this] var bitmap$0: Boolean = false;
      private def b$lzycompute(): test.ImpA$B = {
        {
          ImpA.this.synchronized({
            if (ImpA.this.bitmap$0.unary_!())
              {
                ImpA.this.b = new test.ImpA$B(ImpA.this);
                ImpA.this.bitmap$0 = true;
                ()
              };
            scala.runtime.BoxedUnit.UNIT
          });
          ()
        };
        ImpA.this.b
      };
      lazy private[this] var b: test.ImpA$B = _;
      <stable> <accessor> lazy def b(): test.ImpA$B = if (ImpA.this.bitmap$0.unary_!())
        ImpA.this.b$lzycompute()
      else
        ImpA.this.b;
      override def compute(): Unit = {
        ImpA.this.b().b_=(ImpA.this.b().b().+(1));
        {
          (null: Object);
          () 
        }
      };
      override <bridge> <artifact> def compute(): Object = {
        ImpA.this.compute();
        scala.runtime.BoxedUnit.UNIT
      };
      def <init>(): test.ImpA = {
        ImpA.super.<init>();
        ()
      }
    };
    
    class ImpA extends com.testing.A {
      private[this] var a: Int = _;
      <accessor> def a(): Int = ImpA.this.a;
      <accessor> def a_=(x$1: Int): Unit = ImpA.this.a = x$1;
      override def compute(): String = {
        ImpA.this.a_=(1);
        (null: String)
      };
      override <bridge> <artifact> def compute(): Object = ImpA.this.compute();
      def <init>(): com.testing.ImpA = {
        ImpA.super.<init>();
        ImpA.this.a = 0;
        ()
      }
    };
    
    def <init>(): com.testing.A = {
      A.super.<init>();
      A.this.data = A.this.compute();
      ()
    }