簡體   English   中英

特征與Scala中的抽象類

[英]Trait vs Abstract Class in 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)

首先,對代碼進行一些修改(見下文)。 我放棄了這個case因為它與此無關。 我還在Foo2的構造函數中添加了val ,因為在Bar2無法訪問x

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>來說服自己
  • 等於。 僅限BarBar Bar2是的 兩者都可以相同地訪問和使用。 兩者都是單例,它們公開了一個從外部可讀(但不可寫)的成員變量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>();
    ()
  }
}

不,這些不等同,可能會導致以后的初始化順序出現問題。 我為每個代碼添加了完全相同的代碼行,表明它們從不是相同的代碼塊。

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 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM