scala笔记(三)

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
    }
  }
}
相关文章
相关标签/搜索