1. 程式人生 > >學好Spark/Kafka必須要掌握的Scala技術點(二)類、單例/伴生物件、繼承和trait,模式匹配、樣例類(case class)

學好Spark/Kafka必須要掌握的Scala技術點(二)類、單例/伴生物件、繼承和trait,模式匹配、樣例類(case class)

3. 類、物件、繼承和trait

3.1 類

3.1.1 類的定義

Scala中,可以在類中定義類、以在函式中定義函式、可以在類中定義object;可以在函式中定義類,類成員的預設訪問級別是:public

//在Scala中,類不用宣告為public
//Scala原始檔中可以包含多個類,所有這些類都具有公有可見性
class Person {
  //val修飾的變數是隻讀屬性,相當於Java中final修飾的變數,只提供get()
  val id = "1"
  //var修飾的變數,提供get()和set()
  var age: Int = 18
  //類私有欄位,只有本類和本類的伴生物件可以訪問
  private var name = "zs"
  //物件私有欄位只有本類能訪問
  private[this] val pet = "xq"
}

/**(單例物件,靜態物件)
  * 伴生物件:與class名相同,並且在同一個檔案中*/
object Person {
  def main(args: Array[String]): Unit = {
    val p = new Person
//    p.id = "2"//    p.pet
    println(p.id +":"+p.age+":"+p.name)
    p.name = "ls"
    p.age = 20
    println(p.age+":"+p.name)
  }
}

 

3.1.2 構造器

Scala主要分主構造器和輔助構造器兩種:

主構造器裡面的變數會被執行,方法會被載入,呼叫的方法會被執行

輔助構造器(相當於過載的建構函式)不可以直接呼叫超類的主構造器

/**每個類都有主構造器,主構造器的引數直接放置類名後面,可以在主構造器中對欄位賦值,對於主構造器中引數已賦值的在new的時候可以不再賦值
private[com.bigdata] class Study{}:只有com.bigdata或其子包下的類能訪問Stu

class Stu(name:String){}:構造引數name沒有val、var修飾

相當於private[this] name:String ,只有本類能訪問
 class Stu private(name:String){}:private修飾主構造器(私有構造器),只有伴生物件能new */
 
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)

    this.gender = gender
  }
}

 

3.1.3 Class

Scala中類可以通過classOf[A]獲取型別,Object單例/伴生只能通過.getClass獲取。

classOf和getClass區別:

getClass方法得到的是Class[A]的某個子類,而classOf[A]得到是正確的 Class[A],但是去比較的話,這兩個型別是equals為true的。這種細微的差別,體現在型別賦值時,因為java裡的Class[T]是不支援協變的,所以無法把一個 Class[_ < : A] 賦值給一個 Class[A]。

型別檢查和轉換:

Scala Java
obj.isInstanceOf[C]:判斷obj是否屬於C型別 obj instanceof C
obj.asInstanceOf[C]:轉換 (C)obj
classOf[C] C.class

3.2 物件

3.2.1 單例物件和伴生物件

1.單例物件
在Scala中沒有靜態方法和靜態欄位,但是可以使用object這個語法結構來達到同樣的目的。主要作用:
1)存放工具方法和常量
2)高效共享單個不可變的例項
3)單例模式

2.伴生物件
單例物件,不需要new,用【類名.方法】呼叫單例物件中的方法
伴生物件
在scala的類中,與類名相同且與該類在同一個檔案的物件叫伴生物件。類和伴生物件之間可以相互訪問私有的方法和屬性,但類的欄位被private[this]修飾的只有本類能訪問

 

3.2.2 應用程式物件

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

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

 

3.2.3 apply和unapply方法

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

apply方法有點類似於java中的建構函式,接受構造引數變成一個物件。

unapply方法就剛好相反,它是接收一個物件,從物件中提取出相應的值,主要用於模式匹配(後文闡述)中。

def main(args: Array[String]) {
    //呼叫了Array伴生物件的apply方法
    //def apply(x: Int, xs: Int*): Array[Int]
    //arr1中只有一個元素5
    val arr1 = Array(5)
//def apply[T: ClassTag](xs: T*): Array[T] = {}
    var arr2 = Array[Int](8)
    println(arr1.toBuffer)
    //new了一個長度為5的array,數組裡麵包含5個null(沒有指定泛型)
    var arr2 = new Array(5)
}

 

3.3 繼承和trait

在Scala中繼承類的方式和Java一樣都是使用extends關鍵字,繼承多個類後面有with關鍵字。

Scala中沒有介面,而是trait即特質,類似Java1.8中的介面,其中可以包含抽象方法也可以有已實現的方法。

在Scala中重寫一個非抽象的方法(沒有被實現)必須使用override修飾符,抽象方法可以使用也可以不使用override。

trait Flyable {
  def fly(): Unit = { println("I can fly")  }
}
abstract class Animal {
  def run(): Int
  val name: String
}
/*class Human extends Animal with Flyable
  class Human extends Flyable with其他trait(特質)
*/
class Human extends Animal with Flyable {
  val name = "lz"
  //t1、t2、、tn列印n次ABC,t1=(1, 2, 3,4)(a->1,b->2,c->3,d->4)
  val t1, t2,t3, (a, b, c,d) = {
    println("ABC")
    (1, 2, 3,4)
  }
//scala中重寫一個非抽象方法必須使用override關鍵字
  override def fly(): Unit = { println("123") }
//重寫抽象方法可以使用也可以不使用override關鍵字
  def run(): Int = { 1 }
}
object Main {
  def main(args: Array[String]): Unit = {
    val h = new Human
    println(h.t1+":"+h.a+":"+h.b+":"+h.c+":"+h.t2)
  }
}

 

4. 模式匹配和樣例類

4.1 模式匹配

Scala有一個十分強大的模式匹配機制,可以應用到很多場合:如替代Java中的switch語句、型別檢查等。

並且Scala還提供了樣例類,對模式匹配進行了優化,可以快速進行匹配。

// 1. 匹配字串
import scala.util.Random
object Case01 extends App {
  val arr = Array(1, 2, 3)
  val i = arr(Random.nextInt(arr.length))
  i match {
    case 1 => {println(i)}
    case 2 => {println(i)}
//下劃線_:代表匹配其他所有類似於switch語句中default
    case _ => {println(i)}
  }
}

// 2. 匹配型別
import scala.util.Random
object Case02 extends App {
  val arr = Array("a", 1, -2.0, Case02)
  val elem = arr(Random.nextInt(arr.length))
  println(elem)
  elem match {
    case x:Int => {println("Int"+x)}
//模式匹配時可以加守衛條件,如果不符合守衛條件,走case_
    case y:Double if(y>=0) => println("Double "+ y)
    case Case02 => {println("Int"+Case02)}
    case _ => {println("default")}
  }
}

// 3. 匹配陣列
object Case03 extends App {
  /*  val arr = Array(0, 3, 5)
    arr match {
      case Array(1,x,y) => println(x+":"+y)
      case Array(0) => println("only 0")
        //表示匹配首元素是0的陣列
      case Array(0,_*) => println("0 ...")
      case _ => println("else")
    }*/
  /*  val lst = List(0,-1,1,2)
    //head首元素,tail除首元素之外的元素 take從1開始取
    println(lst.head+":"+lst.tail+":"+lst.take(1))
    lst match {
        //首元素0,Nil代表空列表
      case 0 :: Nil => println("only 0")
        //只有兩個元素
      case x :: y :: Nil => println(s"x:$x--y:$y")
      case 0 :: x => println(s"0...$x")//head和tail
      case _ => println("else")
    }*/
  val tup = (-1.2, "a", 5)
  tup match {
    //元組有幾個元素,case後跟的元組也要有幾個元素
    case (1, x, y) => println(s"hello 123 $x , $y")
    case (_, z, 5) => println(z) //前兩個元素為任意值
    case _ => println("else")
  }
  val lst1 = 9 :: (5 :: (2 :: Nil))
  val lst2 = 9 :: 5 :: 2 :: List()
  println(lst2+":"+lst1)//952:952
}

 

4.2 樣例類

可用於模式匹配、封裝資料(多例)。case class多例,後面跟建構函式;case object是單例的:

import scala.util.Random
case class Task(id:String)
case class HeartTime(private val time:Long)//構造case class可new可不new
case object CheckTimeOut

object Main {
    def main(args: Array[String]) {
        val arr = Array(CheckTimeOut, HeartBeat(88888), Task("0001"))
        val a = arr(Random.nextInt(arr.length))

       a match {
            case Task(id) => {println(s"$id")}//取id值 固定寫法
            case HeartTime(time) => {println(s"$time")}
            case CheckTimeOutTask => {
                println("check")
            }
            
            //匹配其他情況
            case _ => prinln("do something")
         }
    }
}

 


 

關注微信公眾號:大資料學習與分享,獲取更對技術