1. 程式人生 > >Scala入門到精通——第十節 Scala類層次結構、Traits初步

Scala入門到精通——第十節 Scala類層次結構、Traits初步

本節主要內容

  1. Scala類層次結構總覽
  2. Scala中原生型別的實現方式解析
  3. Nothing、Null型別解析
  4. Traits簡介
  5. Traits幾種不同使用方式

1 Scala類層次結構

Scala中的類層次結構圖如下:

這裡寫圖片描述
來源:Programming in Scala

從上面的類層次結構圖中可以看到,處於繼承層次最頂層的是Any類,它是scala繼承的根類,scala中所有的類都是它的子類
Any類中定義了下面幾個方法:

//==與!=被宣告為final,它們不能被子類重寫
final def ==(that: Any): Boolean
final def !=(that: Any): Boolean
def
equals(that: Any): Boolean def hashCode: Int def toString: String

從上面的程式碼看可以看到,Any類中共包括了五個方法,其中==與!=被宣告為final型別的,因此它們不能被子類重寫,事實上==的真正實現是通過equals方法來實現的,而!=是通過!equals來實現的,因此如果想改變==與!=方法的行為的話,可以直接對equals進行重寫。

根類Any有兩個子類,它們分別是AnyVal和AnyRef,其中AnyVal是所有scala內建的值型別( Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit.)的父類,其中 Byte, Short, Char, Int, Long, Float, Double, Boolean與java中的byte,short,char,int,long,float,double,boolean原生型別對應,而Unit對應java中的void型別,由於( Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit)繼承AnyVal,而AnyVal又繼承Any,因此它們也可以呼叫toString等方法。

scala> 2.0.hashCode
res5: Int = 1073741824

scala> 2.0 toString
res6: String = 2.0

值得一提的是,()可以作為Unit型別的例項,它同樣可以呼叫toString等方法

scala> ().hashCode
res7: Int = 0

scala> ().toString
res8: String = ()

scala> ()==()
<console>:8: warning: comparing values of types Unit and Unit using `=='
will al ways yield true ()==() ^ res9: Boolean = true

AnyRef是Any的另外一個子類,它是scala中所有非值型別的父類,對應Java.lang.Object類(可以看作是java.lang.Object類的別名),也即它是所有引用型別的父類(除值型別外)。那為什麼不直接Java.lang.Object作為scala非值引用型別的父類呢?這是因為Scala還可以執行在其它平臺上如.Net,所以它使用了AnyRef這個類,在JVM上它對應的是java.lang.Object,而對於其它平臺有不同的實現。

2 Scala中原生型別的實現方式解析

scala採用與java相同原生型別儲存方式,由於效能方面及與java進行操作方面的考慮,scala對於原生型別的基本操作如加減乘除操作與java是一樣的,當需要遇到其他方法呼叫時,則使用java的原生型別封裝類來表示,如Int型別對應於java.lang.Integer型別,這種轉換對於我們使用者來說是透明的。

在本課程的第二節中我們提到,scala中的==操作它不區分你是原生型別還是引用型別,例如

scala> "abc"=="abc"
res10: Boolean = true

如果是在java語言中,它返回的是false。在scala中,對於原生型別,這種等於操作同java原生型別,而對於引用型別,它實際上是用equals方法對==方法進行實現,這樣避免了程式設計時存在的某些問題。那如果想判斷兩個引用型別是否相等時怎麼辦呢? AnyRef中提供了eq、ne兩個方法用於判斷兩個引用是否相等,如

scala> val x=new String("123")
x: String = 123

scala> val y=new String("123")
y: String = 123

scala> x==y
res15: Boolean = true

scala> x.eq(y)
res16: Boolean = false

scala> x ne y
res17: Boolean = true

3 Nothing、Null型別解析

在前面的類層次結構圖中可以看到,Null型別是所有AnyRef型別的子型別,也即它處於AnyRef類的底層,對應java中的null引用。而Nothing是scala類中所有類的子類,它處於scala類的最底層。
這裡面必須注意的是Null型別處於AnyRef類的底層,它不能夠作為值型別的子類,例如:

scala> var x:Int=null
<console>:7: error: type mismatch;
 found   : Null(null)
 required: Int
Note that implicit conversions are not applicable because they are ambiguous:
 both method Integer2intNullConflict in class LowPriorityImplicits of type (x: N
ull)Int
 and method Integer2int in object Predef of type (x: Integer)Int
 are possible conversion functions from Null(null) to Int
       var x:Int=null
                 ^

Nothing這個類一般用於指示程式返回非正常結果,利用Nothing作為返回值可以增加程式的靈活性。例如:

 def error(msg:String):Nothing={
    throw new RuntimeException(msg)
  }

def divide(x: Int, y: Int): Int =
if (y != 0) x / y
else error("can't divide by zero")

4 Traits簡介

scala和java語言一樣,採用了很強的限制策略,避免了多種繼承的問題。在java語言中,只允許繼承一個超類,該類可以實現多個介面,但java介面有其自身的侷限性:介面中只能包括抽象方法,不能包含欄位、具體方法。Scala語言利用Trait解決了該問題,在scala的trait中,它不但可以包括抽象方法還可以包含欄位和具體方法。trait的示例如下:

//trait定義演示
trait DAO{
  //定義一個抽象方法,注意不需要加abstract
  //加了abstract反而會報錯
  def delete(id:String):Boolean
  def add(o:Any):Boolean
  def update(o:Any):Int
  def query(id:String):List[Any]
}

生成的位元組碼檔案反編譯後的結果:

D:\ScalaWorkspace\ScalaChapter10\bin\cn\scala\xtwy>javap -private DAO.class
Compiled from "Dao.scala"
public interface cn.scala.xtwy.DAO {
  public abstract boolean delete(java.lang.String);
  public abstract boolean add(java.lang.Object);
  public abstract int update(java.lang.Object);
  public abstract scala.collection.immutable.List<java.lang.Object> query(java.l
ang.String);
}

下面的程式碼演示瞭如果使用trait

trait MysqlDAO{
  def add(o:Any):Boolean
  def update(o:Any):Int
  def query(id:String):List[Any]
}

class DaoImpl extends MysqlDAO{
  def add(o:Any):Boolean=true
  def update(o:Any):Int= 1
   def query(id:String):List[Any]=List(1,2,3)
}

如果有多個trait的話:

trait MysqlDAO{
  var recodeMount:Long=15000000000000L
  def add(o:Any):Boolean
  def update(o:Any):Int
  def query(id:String):List[Any]
}

class DaoImpl extends MysqlDAO with Cloneable{
  def add(o:Any):Boolean=true
  def update(o:Any):Int= 1
  def query(id:String):List[Any]=List(1,2,3)
}

5 Traits幾種不同使用方式

1 當做java介面使用的trait,如

//trait定義演示
trait DAO{
  //定義一個抽象方法,注意不需要加abstract
  //加了abstract反而會報錯
  def delete(id:String):Boolean
  def add(o:Any):Boolean
  def update(o:Any):Int
  def query(id:String):List[Any]
}

2 帶具體實現的trait

trait DAO{
  //delete方法有具體實現
  def delete(id:String):Boolean={
    println("delete implementation")
    true
  }
  def add(o:Any):Boolean
  def update(o:Any):Int
  def query(id:String):List[Any]
}

這裡定義的特質將生成兩個位元組碼檔案:

 D:\ScalaWorkspace\ScalaChapter10\bin\cn\scala\xtwy 的目錄

2015/07/25  22:20    <DIR>          .
2015/07/25  22:20    <DIR>          ..
2015/07/25  22:20               575 DAO$class.class
2015/07/25  22:20               898 DAO.class
               2 個檔案          1,473 位元組
               2 個目錄 175,333,232,640 可用位元組


D:\ScalaWorkspace\ScalaChapter10\bin\cn\scala\xtwy>javap -private DAO$class.class
Compiled from "Dao.scala"
public abstract class cn.scala.xtwy.DAO$class {
  public static boolean delete(cn.scala.xtwy.DAO, java.lang.String);
  public static void $init$(cn.scala.xtwy.DAO);
}

D:\ScalaWorkspace\ScalaChapter10\bin\cn\scala\xtwy>javap -private DAO.class
Compiled from "Dao.scala"
public abstract class cn.scala.xtwy.DAO$class {
  public static boolean delete(cn.scala.xtwy.DAO, java.lang.String);
  public static void $init$(cn.scala.xtwy.DAO);
}

從位元組碼檔案可以看出,帶有具體實現的trait是通過java中的抽象類來實現的。

3 帶抽象欄位的trait

trait DAO{
  var recodeMount:Long

  def delete(id:String):Boolean={
    println("delete implementation")
    true
  }
  def add(o:Any):Boolean
  def update(o:Any):Int
  def query(id:String):List[Any]
}

4 具體欄位的trait

trait DAO{
  var recodeMount:Long=15000000000000L

  def delete(id:String):Boolean={
    println("delete implementation")
    true
  }
  def add(o:Any):Boolean
  def update(o:Any):Int
  def query(id:String):List[Any]
}

新增公眾微訊號,可以瞭解更多最新Spark、Scala相關技術資訊
這裡寫圖片描述