特征与Scala中的抽象类

时间:2015-10-05 22:34:40

标签: scala

假设没有多重继承并且不担心与Java的互操作性,以下两个声明是否相等?

sealed trait Foo { def x: Int }
case object Bar extends Foo { val x = 5 }

sealed abstract class Foo(val x: Int)
case object Bar extends Foo(5)

2 个答案:

答案 0 :(得分:1)

不,这些不等同,可能会导致以后的初始化顺序出现问题。我已经为每个代码添加了完全相同的代码行,表明它们永远不会是相同的代码块。

sealed trait Foo {
    def x: Int
    val calc = x * 5 / 2  //at the time this runs, x is actually 0
  }
  case object Bar extends Foo {
    val x = 5

  }


  sealed abstract class Foo2(x: Int){
    val calc = x * 5 / 2
  }
  case object Bar2 extends Foo2(5)

  println(Bar.calc)
  println(Bar2.calc)

  //output  0  12 

答案 1 :(得分:1)

首先,对您的代码进行一些修改(见下文)。我放弃了case,因为这里不相关。我还在val的构造函数中添加了Foo2,因为x无法访问Bar2

sealed trait Foo { def x: Int }
object Bar extends Foo { val x = 5 }

sealed abstract class Foo2(val x: Int)
object Bar2 extends Foo2(5)

object Main {
  def main(args: Array[String]) : Unit = {
    println( Bar.x )
    println( Bar2.x )
  }
}
  

以下两个声明是否相等?

我们需要定义相等的含义:

  • 等于。一般结构:。特质不是抽象类。特征可以没有构造函数参数,而类可以。另一方面,类或对象(此处为Bar2)只能从一个(抽象)类派生,而它可以混合多个特征。这里给出了关于特征与抽象类的良好补偿:http://www.artima.com/pins1ed/traits.html#12.7如果你需要决定一个特征或一个类。
  • 等于。字节代码:。只需运行javap -v <classfile>来说服自己
  • 等于。仅BarBar2。两者都可以相同地访问和使用。两者都是单例,它们公开了一个从外部可读(但不可写)的成员变量x

scalac -print的输出也非常有用,看看发生了什么:

sealed abstract trait Foo extends Object {
  def x(): Int
};
object Bar extends Object with com.Foo {
  private[this] val x: Int = _;
  <stable> <accessor> def x(): Int = Bar.this.x;
  def <init>(): com.Bar.type = {
    Bar.super.<init>();
    Bar.this.x = 5;
    ()
  }
};
sealed abstract class Foo2 extends Object {
  <paramaccessor> private[this] val x: Int = _;
  <stable> <accessor> <paramaccessor> def x(): Int = Foo2.this.x;
  def <init>(x: Int): com.Foo2 = {
    Foo2.this.x = x;
    Foo2.super.<init>();
    ()
  }
};
object Bar2 extends com.Foo2 {
  def <init>(): com.Bar2.type = {
    Bar2.super.<init>(5);
    ()
  }
};
object Main extends Object {
  def main(args: Array[String]): Unit = {
    scala.this.Predef.println(scala.Int.box(Bar.x()));
    scala.this.Predef.println(scala.Int.box(Bar2.x()))
  };
  def <init>(): com.Main.type = {
    Main.super.<init>();
    ()
  }
}