Scala入门到精通——第十节 Scala类层次结构、Traits初步
本節主要內容
1 Scala類層次結構
Scala中的類層次結構圖如下:
來源:Programming in scala
從上面的類層次結構圖中可以看到,處于繼承層次最頂層的是Any類,它是scala繼承的根類,scala中所有的類都是它的子類
Any類中定義了下面幾個方法:
從上面的代碼看可以看到,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 = 1073741824scala> 2.0 toString res6: String = 2.0值得一提的是,()可以作為Unit類型的實例,它同樣可以調用toString等方法
scala> ().hashCode res7: Int = 0scala> ().toString res8: String = ()scala> ()==() <console>:8: warning: comparing values of types Unit and Unit using `==' will al ways yield true ()==() ^ res9: Boolean = trueAnyRef是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 = 123scala> val y=new String("123") y: String = 123scala> x==y res15: Boolean = truescala> x.eq(y) res16: Boolean = falsescala> x ne y res17: Boolean = true3 Nothing、Null類型解析
在前面的類層次結構圖中可以看到,Null類型是所有AnyRef類型的子類型,也即它處于AnyRef類的底層,對應java中的null引用。而Nothing是scala類中所有類的子類,它處于scala類的最底層。
這里面必須注意的是Null類型處于AnyRef類的底層,它不能夠作為值類型的子類,例如:
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")- 1
4 Traits簡介
scala和java語言一樣,采用了很強的限制策略,避免了多種繼承的問題。在java語言中,只允許繼承一個超類,該類可以實現多個接口,但java接口有其自身的局限性:接口中只能包括抽象方法,不能包含字段、具體方法。Scala語言利用Trait解決了該問題,在scala的trait中,它不但可以包括抽象方法還可以包含字段和具體方法。trait的示例如下:
//trait定義演示 trait DAO{//定義一個抽象方法,注意不需要加abstract//加了abstract反而會報錯def delete(id:String):Booleandef add(o:Any):Booleandef update(o:Any):Intdef query(id:String):List[Any] }- 1
生成的字節碼文件反編譯后的結果:
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); }- 1
下面的代碼演示了如果使用trait
trait MysqlDAO{def add(o:Any):Booleandef update(o:Any):Intdef query(id:String):List[Any] }class DaoImpl extends MysqlDAO{def add(o:Any):Boolean=truedef update(o:Any):Int= 1def query(id:String):List[Any]=List(1,2,3) }- 1
如果有多個trait的話:
trait MysqlDAO{var recodeMount:Long=15000000000000Ldef add(o:Any):Booleandef update(o:Any):Intdef query(id:String):List[Any] }class DaoImpl extends MysqlDAO with Cloneable{def add(o:Any):Boolean=truedef update(o:Any):Int= 1def query(id:String):List[Any]=List(1,2,3) }5 Traits幾種不同使用方式
1 當做java接口使用的trait,如
//trait定義演示 trait DAO{//定義一個抽象方法,注意不需要加abstract//加了abstract反而會報錯def delete(id:String):Booleandef add(o:Any):Booleandef update(o:Any):Intdef query(id:String):List[Any] }2 帶具體實現的trait
trait DAO{//delete方法有具體實現def delete(id:String):Boolean={println("delete implementation")true}def add(o:Any):Booleandef update(o:Any):Intdef 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.class2 個文件 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); }- 3
從字節碼文件可以看出,帶有具體實現的trait是通過java中的抽象類來實現的。
3 帶抽象字段的trait
trait DAO{var recodeMount:Longdef delete(id:String):Boolean={println("delete implementation")true}def add(o:Any):Booleandef update(o:Any):Intdef query(id:String):List[Any] }4 具體字段的trait
trait DAO{var recodeMount:Long=15000000000000Ldef delete(id:String):Boolean={println("delete implementation")true}def add(o:Any):Booleandef update(o:Any):Intdef query(id:String):List[Any] }總結
以上是生活随笔為你收集整理的Scala入门到精通——第十节 Scala类层次结构、Traits初步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Scala入门到精通——第九节 继承与组
- 下一篇: Scala入门到精通——第十一节 Tra