1. 程式人生 > >[大資料]Scala 速學手冊2

[大資料]Scala 速學手冊2

Scala 速學手冊2

1 類、物件、繼承、特質

1.1 類

1 類的定義

//在Scala中,類並不用宣告為public。
//Scala原始檔中可以包含多個類,所有這些類都具有公有可見性。
class Person {
  //用val修飾的變數是隻讀屬性,有getter但沒有setter
  //(相當與Java中用final修飾的變數)
  val id = "9527"

  //用var修飾的變數既有getter又有setter
  var age: Int = 18

  //類私有欄位,只能在類的內部使用
  private var name: String = "唐伯虎"

  //物件私有欄位,訪問許可權更加嚴格的,Person類的方法只能訪問到當前物件的欄位
  private[this] val pet = "小強"
}

2 類的構造器
注意:主構造器會執行類定義中的所有語句

/**
  *每個類都有主構造器,主構造器的引數直接放置類名後面,與類交織在一起
  */
class Student(val name: String, val age: Int){
  //主構造器會執行類定義中的所有語句
  println("執行主構造器")

  try {
    println("讀取檔案")
    throw new IOException("io exception")
  } catch {
    case e: NullPointerException => println("列印異常Exception : " + e)
    case e: IOException => println("列印異常Exception : " + e)
  } finally {
    println("執行finally部分")
  }

  private var gender = "male"

  //用this關鍵字定義輔助構造器
  def this(name: String, age: Int, gender: String){
    //每個輔助構造器必須以主構造器或其他的輔助構造器的呼叫開始
    this(name, age)
    println("執行輔助構造器")
    this.gender = gender
  }
}



/**
  *構造器引數可以不帶val或var,如果不帶val或var的引數至少被一個方法所使用,
  *那麼它將會被提升為欄位
  */
//在類名後面加private就變成了私有的
class Queen private(val name: String, prop: Array[String], private var age: Int = 18){
  
  println(prop.size)

  //prop被下面的方法使用後,prop就變成了不可變得物件私有欄位,等同於private[this] val prop
  //如果沒有被方法使用該引數將不被儲存為欄位,僅僅是一個可以被主構造器中的程式碼訪問的普通引數
  def description = name + " is " + age + " years old with " + prop.toBuffer
}

object Queen{
  def main(args: Array[String]) {
    //私有的構造器,只有在其伴生物件中使用
    val q = new Queen("hatano", Array("蠟燭", "皮鞭"), 20)
    println(q.description())
  }
}

1.2 物件

在Scala中沒有靜態方法和靜態欄位,但是可以使用object這個語法結構來達到同樣的目的

  1. 存放工具方法和常量
  2. 高效共享單個不可變的例項
  3. 單例模式
import scala.collection.mutable.ArrayBuffer


object SingletonDemo {
  def main(args: Array[String]) {
    //單例物件,不需要new,用【類名.方法】呼叫物件中的方法
    val session = SessionFactory.getSession()
    println(session)
  }
}

object SessionFactory{
  //該部分相當於java中的靜態塊
  var counts = 5
  val sessions = new ArrayBuffer[Session]()
  while(counts > 0){
    sessions += new Session
    counts -= 1
  }

  //在object中的方法相當於java中的靜態方法
  def getSession(): Session ={
    sessions.remove(0)
  }
}

class Session{

}

2 伴生物件

在Scala的類中,與類名相同的物件叫做伴生物件,類和伴生物件之間可以相互訪問私有的方法和屬性

class Dog {
  val id = 1
  private var name = "herry"

  def printName(): Unit ={
    //在Dog類中可以訪問伴生物件Dog的私有屬性
    println(Dog.CONSTANT + name )
  }
}

/**
  * 伴生物件
  */
object Dog {

  //伴生物件中的私有屬性
  private val CONSTANT = "汪汪汪 : "

  def main(args: Array[String]) {
    val p = new Dog
    //訪問私有的欄位name
    p.name = "123"
    p.printName()
  }
}

3 apply方法

通常我們會在類的伴生物件中定義apply方法,當遇到類名(引數1,…引數n)時apply方法會被呼叫

object ApplyDemo {
  def main(args: Array[String]) {
    //呼叫了Array伴生物件的apply方法
    //def apply(x: Int, xs: Int*): Array[Int]
    //arr1中只有一個元素5
    val arr1 = Array(5)
    println(arr1.toBuffer)

    //new了一個長度為5的array,數組裡麵包含5個null
    var arr2 = new Array(5)
  }
}

4 應用程式物件

Scala程式都必須從一個物件的main方法開始,可以通過擴充套件App特質,不寫main方法。

object AppObjectDemo extends App{
  //不用寫main方法
  println("I love you Scala")
}

1.2 繼承

1 擴充套件類

在Scala種擴充套件類的方法和Java一樣都是使用extends 關鍵字

2 重寫方法

在Scala種重寫一個非抽象的方法必須使用override修飾符

3 型別檢查和轉換

scala java
obj.isInstanceOf[C] obj instanceof C
obj.asInstanceOf[C] ©obj
classOf[C] C.class

超類的構造

object ClazzDemo {
  def main(args: Array[String]) {
    val h = new Human
    println(h.fight)
  }
}
//類似介面
trait Flyable{
  def fly(): Unit ={
    println("I can fly")
  }

  def fight(): String
}

abstract class Animal {
  def run(): Int
  val name: String
}

class Human extends Animal with Flyable{

  val name = "abc"

  //列印幾次"ABC"?
  val t1,t2,(a, b, c) = {
    println("ABC")
    (1,2,3)
  }

  println(a)
  println(t1._1)

  //在Scala中重寫一個非抽象方法必須用override修飾
  override def fight(): String = {
    "fight with 棒子"
  }
  //在子類中重寫超類的抽象方法時,不需要使用override關鍵字,寫了也可以
  def run(): Int = {
    1
  }
}

2 模式匹配和樣例類

Scala有一個十分強大的模式匹配機制,可以應用到很多場合:如switch語句、型別檢查等。並且Scala還提供了樣例類,對模式匹配進行了優化,可以快速進行匹配

2.1 匹配字串

 import scala.util.Random

object CaseDemo01 extends App{
  val arr = Array("YoshizawaAkiho", "YuiHatano", "AoiSola")
  val name = arr(Random.nextInt(arr.length))
  name match {
    case "YoshizawaAkiho" => println("吉澤老師...")
    case "YuiHatano" => println("波多老師...")
    case _ => println("真不知道你們在說什麼...")
  }
}

2.2 匹配型別

注意:case y: Double if(y >= 0) => …

模式匹配的時候還可以新增守衛條件。如不符合守衛條件,將掉入case _中

import scala.util.Random

object CaseDemo01 extends App{
  //val v = if(x >= 5) 1 else if(x < 2) 2.0 else "hello"
  val arr = Array("hello", 1, 2.0, CaseDemo)
  val v = arr(Random.nextInt(4))
  println(v)
  v match {
    case x: Int => println("Int " + x)
    case y: Double if(y >= 0) => println("Double "+ y)
    case z: String => println("String " + z)
    case _ => throw new Exception("not match exception")
  }
}

2.3 匹配陣列、元組

注意: 在Scala中列表要麼為空(Nil表示空列表)要麼是一個head元素加上一個tail列表。

9 :: List(5, 2) :: 操作符是將給定的頭和尾建立一個新的列表

注意: :: 操作符是右結合的,如9 :: 5 :: 2 :: Nil相當於 9 :: (5 :: (2 :: Nil))

object CaseDemo03 extends App{

  val arr = Array(1, 3, 5)
  arr match {
    case Array(1, x, y) => println(x + " " + y)
    case Array(0) => println("only 0")
    case Array(0, _*) => println("0 ...")
    case _ => println("something else")
  }

  val lst = List(3, -1)
  lst match {
    case 0 :: Nil => println("only 0")
    case x :: y :: Nil => println(s"x: $x y: $y")
    case 0 :: tail => println("0 ...")
    case _ => println("something else")
  }

  val tup = (2, 3, 7)
  tup match {
    case (1, x, y) => println(s"1, $x , $y")
    case (_, z, 5) => println(z)
    case  _ => println("else")
  }
}

2.4 樣例類

在Scala中樣例類是一中特殊的類,可用於模式匹配。case class是多例的,後面要跟構造引數,case object是單例的

import scala.util.Random

case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask

object CaseDemo04 extends App{
  val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))

  arr(Random.nextInt(arr.length)) match {
    case SubmitTask(id, name) => {
      println(s"$id, $name")//前面需要加上s, $id直接取id的值
    }
    case HeartBeat(time) => {
      println(time)
    }
    case CheckTimeOutTask => {
      println("check")
    }
  }
}

2.5 Option型別

在Scala中Option型別樣例類用來表示可能存在或也可能不存在的值(Option的子類有Some和None)。Some包裝了某個值,None表示沒有值


object OptionDemo {
  def main(args: Array[String]) {
    val map = Map("a" -> 1, "b" -> 2)
    val v = map.get("b") match {
      case Some(i) => i
      case None => 0
    }
    println(v)
    //更好的方式
    val v1 = map.getOrElse("c", 0)
    println(v1)
  }
}

2.6 偏函式

被包在花括號內沒有match的一組case語句是一個偏函式,它是PartialFunction[A, B]的一個例項,A代表引數型別,B代表返回型別,常用作輸入模式匹配

object PartialFuncDemo  {

  def func1: PartialFunction[String, Int] = {
    case "one" => 1
    case "two" => 2
    case _ => -1
  }

  def func2(num: String) : Int = num match {
    case "one" => 1
    case "two" => 2
    case _ => -1
  }

  def main(args: Array[String]) {
    println(func1("one"))
    println(func2("one"))
  }
}