1、特質
1.特質更像是抽象類,有抽象的方法也能夠有具體方法,抽象字段和具體字段,不能有類參數,有不一樣的地方是,super是動態綁定的,即寫super.進行方法調用時沒辦法斷定綁定的是哪一個特質或類的方法,只有在混入具體的類時(scala能夠多繼承)才能斷定。還有特質的定義使用trait關鍵字。
使用特質能夠用extends或者with關鍵字混入類或者抽象類中。java
trait A { def speak() = println("I am balabala!") } //B繼承A特質 class B extends A{} class C {} //若是類有顯式的父類,混入A特質時則須要使用with關鍵字 //可使用多個with關鍵字混入多個特質,看起來會由於多重繼承引發方法調用不明確的問題 //這個稍後會解釋在scala中如何處理 trait B { def speak() = println("I am balabala!") } class D extends C with A with B
2.Order特質
兩個同一類型的對象的比較時,只須要在類實現時繼承Ordered特質並實現compare方法就能夠實現對象的>、<、>=和<=的比較。例如:ide
class Test(val a:Int) extends Ordered[Test]{ def compare(that:Test){ this.a - that.a } } val a = new Test(1) val b = new Test(2) println(a > b) println(a >= b) println(a < b) println(a <= b)
3.特質堆疊
個人理解來講,特質的堆疊解釋了一個多重繼承的問題,scala中的解決方法是線性化。依然仍是舉書上的栗子吧:
假設實現一個抽象的整數隊列,有兩種操做,一種是put,把整數放入隊列,另一種是get,從隊列尾部取出一個整數。工具
abstract class IntQueue{ def get():Int def put(x:Int) } //一個實現類: class BasicIntQueue extends IntQueue{ private val buf = new ArrayBuffer[Int] def get() = buf.remove(0) def put(x:Int) {buf += x} }
定義了三個特質以下:ui
//1.特質繼承自IntQueue,則特質只能混入IntQueue及其子類中 //2.特質中的super調用是線性化調用,只有在混入類或者特質的時候纔會有意義 //3.abstract override標識符僅在物質成員定義中可使用, //意味着特質必須被混入具備期待方法的具體的類中。 //將放入隊列的數字加倍 trait Doubling extends IntQueue{ abstract override def put(x:Int) {super.put(2 * x)} } //將放入隊列的數字加1 trait Incrementing extends IntQueue{ abstract override def put(x:Int) {super.put(x + 1)} } //過濾放入隊列的數字,若是爲負數則不放入隊列。 trait Filtering extends IntQueue{ abstract override def put(x:Int) {if(x >= 0) super.put(x)} } //這個是普通的使用,沒有多繼承的問題 val queue = new BasicIntQueue with Doubling queue.put(10) queue.get()//20 //如下這個類混入兩個特質,put方法調用的是哪一個呢,答案是put的調用順序從右向左依次 //調用,先調用Filtering的而後是Incrementing的,因此結果是第一個put的值會先被 //過濾掉,而第二和第三個則不會被過濾,而後纔會調用Incrementing的put方法加1, //最後調用BasicIntQueue的put方法存入隊列。 val myQueue = new BasicIntQueue with Incrementing with Filtering myQueue.put(-1) myQueue.put(0) myQueue.put(1) myQueue.get()//1 myQueue.get()//2 //也能夠調整一下特質混入的順序以下,則會先調用Incrementing的put方法加1, //而後才調用Filtering的put方法過濾負數,因此會產生以下結果: val otherQueue = new BasicIntQueue with Filtering with Incrementing otherQueue.put(-1) otherQueue.put(0) otherQueue.put(1) otherQueue.get()//0 otherQueue.get()//1 otherQueue.get()//2
4.線性化
線性化,當使用new實例化一個類的時候,scala把這個類以及全部它繼承的類還有它混入的特質以線性的次序放在一塊兒。當其中某個類調用super的時候指的就是這個線性次序的下一個環節。this
2、包和引用
1.普通寫法的和Java中一致,如package com.aaa.bbb
另一種寫法則能夠將同一文件中的不一樣類放到不一樣包中,好比:scala
package com{ package aaa{ //屬於包com.aaa class App{} package bbb{ //屬於包com.aaa.bbb class TestApp{} } } } //還有另外一種簡寫的方式 package com.aaa{ class App{} package bbb{ class TestApp{} } }
2.scala中包的簡單寫法code
package com{ package aaa{ class App{} } package bbb{ //這裏的引用能夠不寫絕對路徑 //另外scala中提供了一個—_root_包,它是全部用戶建立的包的頂層包 //即下面的包也能夠寫成_root_.com.aaa.App,只是爲了舉例,這個頂層 //包的做用是爲了子包和上層的包名有衝突時使用的 val test = new aaa.App } }
3.包引用
引入的方式對象
//引入com.aaa.bbb包 import com.aaa.bbb //引入com.aaa包下的全部成員 import com.aaa._ //引入類APP下的全部成員 import com.aaa.APP._ //引入aaa包下的AA和BB成員 import com.aaa.{AA,BB} //引入aaa包下的AA和BB成員,並把AAA重命名爲A,可使用A代替AAA import com.aaa.{AAA => A,BB} //引入aaa包下的全部成員,並把AAA重命名爲A,可使用A代替AAA import com.aaa.{AAA => A,_} //引入aaa包下的除AAA外的全部成員, import com.aaa.{AAA => _,_}
scala中的包引用能夠放到任何地方,好比能夠放到一個方法中:繼承
def test(p:Person){ //以下引用則能夠直接使用Person類中的成員 import p._ println(name+"--"+age) }
每個scala類中都默認引用了三個包,java.lang.,scala.,Predef._分別是java和scala的標準庫還有scala中的經常使用的工具類。若是有相同成員,後引用的將會覆蓋先引用的,好比:StringBuilder在java.lang和scala中都有,則默認會引用scala中的。隊列
4.訪問修飾符
private與Java中相似只能在類或者對象的內部訪問,而且規則也應用到內部類上,好比:
class Outer{ class Inner{ private def f() {println("fun")} class InnerMost{ //能夠調用 f() } } //不能夠,由於不在Inner類內部 (new Inner).f() }
protected也相對比Java中的限制要多一些,好比:
package p{ class Super{X protected def fun() {println("fun")} } class Sub extends Super{ fun() } class Other{ //不能夠,由於不是Super的子類 fun() } }
public成員沒有顯示的標識符,只要沒有明確標識Private或者protected的成員都是public,在任何地方均可以訪問
做用域
scala中有更爲細顆粒度的控制,好比private[X]或者protected[X],X指的能夠是包、類或者單例對象,示例:
package bobsrockets{ package navigation{ private[bobsrockets] class Navigator{ //在navigation包和Navigator類及之類中可見 protected[navigation] def userStarChart(){} class LegOfJourney{ //在類Navigator中可見 private[Navigator] val distance = 100 } //只在Navigator的同一個實例中可見 private[this] var speed = 200 } } package lanuch{ import navigation._ object Vehicle{ //lanuch包在bobsrockets中,根據private[Navigator]這個定義,則能夠訪問Navigator類 private[lanuch] val guide = new Navigator } } }