帶你快速掌握Scala操作———(5)

1、類型判斷

有時候,我們設計的程序,要根據變量的類型來執行對應的邏輯。

在這裏插入圖片描述

在scala中,如何來進行類型判斷呢?

有兩種方式:
	isInstanceOf
	getClass/classOf
isInstanceOf/asInstanceOf
在Java中,可以使用instanceof關鍵字來判斷類型、以及(類型)object來進行類型轉換,在scala中如何實現?
scala中對象提供isInstanceOf和asInstanceOf方法。
	isInstanceOf判斷對象是否爲指定類的對象
	asInstanceOf將對象轉換爲指定類型

用法

// 判斷對象是否爲指定類型
val trueOrFalse:Boolean = 對象.isInstanceOf[類型]
// 將對象轉換爲指定類型
val 變量 = 對象.asInstanceOf[類型]

示例

示例說明
	定義一個Person類
	定義一個Student類繼承自Person類
	創建一個Student類對象
	判斷該對象是否爲Student類型,如果是,將其轉換爲Student類型並打印該對象

參考代碼

class Person3
class Student3 extends Person3

object Main3 {
  def main(args: Array[String]): Unit = {
    val s1:Person3 = new Student3

    // 判斷s1是否爲Student3類型
    if(s1.isInstanceOf[Student3]) {
      // 將s1轉換爲Student3類型
      val s2 =  s1.asInstanceOf[Student3]
      println(s2)
    }

  }
}

2、getClass和classOf

isInstanceOf 只能判斷對象是否爲指定類以及其子類的對象,而不能精確的判斷出,對象就是指定類的對象。如果要求精確地判斷出對象就是指定類的對象,那麼就只能使用 getClass 和 classOf 。

用法

	p.getClass可以精確獲取對象的類型
	classOf[x]可以精確獲取類型
	使用==操作符可以直接比較類型

示例

示例說明
	定義一個Person類
	定義一個Student類繼承自Person類
	創建一個Student類對象,並指定它的類型爲Person類型
	測試使用isInstance判斷該對象是否爲Person類型
	測試使用getClass/classOf判斷該對象是否爲Person類型
	測試使用getClass/classOf判斷該對象是否爲Student類型

參考代碼

class Person4
class Student4 extends Person4

object Student4{
  def main(args: Array[String]) {
    val p:Person4=new Student4
    //判斷p是否爲Person4類的實例
    println(p.isInstanceOf[Person4])//true

    //判斷p的類型是否爲Person4類
    println(p.getClass == classOf[Person4])//false

    //判斷p的類型是否爲Student4類
    println(p.getClass == classOf[Student4])//true
  }

3、抽象類

和Java語言一樣,scala中也可以定義抽象類

定義

如果類的某個成員在當前類中的定義是不包含完整的,它就是一個抽象類

不完整定義有兩種情況:

1.	方法沒有方法體(抽象方法)
2.	變量沒有初始化(抽象字段)
定義抽象類和Java一樣,在類前面加上abstract關鍵字
// 定義抽象類
abstract class 抽象類名 {
  // 定義抽象字段
  val 抽象字段名:類型
  // 定義抽象方法
  def 方法名(參數:參數類型,參數:參數類型...):返回類型
}
抽象方法

示例

在這裏插入圖片描述

•	設計4個類,表示上述圖中的繼承關係
•	每一個形狀都有自己求面積的方法,但是不同的形狀計算面積的方法不同

步驟

1.	創建一個Shape抽象類,添加一個area抽象方法,用於計算面積
2.	創建一個Square正方形類,繼承自Shape,它有一個邊長的主構造器,並實現計算面積方法
3.	創建一個長方形類,繼承自Shape,它有一個長、寬的主構造器,實現計算面積方法
4.	創建一個圓形類,繼承自Shape,它有一個半徑的主構造器,並實現計算面積方法
5.	編寫main方法,分別創建正方形、長方形、圓形對象,並打印它們的面積

參考代碼

// 創建形狀抽象類
abstract class Shape {
  def area:Double
}

// 創建正方形類
class Square(var edge:Double /*邊長*/) extends Shape {
  // 實現父類計算面積的方法
  override def area: Double = edge * edge
}

// 創建長方形類
class Rectangle(var length:Double /*長*/, var width:Double /*寬*/) extends Shape {
  override def area: Double = length * width
}

// 創建圓形類
class Cirle(var radius:Double /*半徑*/) extends Shape {
  override def area: Double = Math.PI * radius * radius
}

object Main6 {
  def main(args: Array[String]): Unit = {
    val s1:Shape = new Square(2)
    val s2:Shape = new Rectangle(2,3)
    val s3:Shape = new Cirle(2)

    println(s1.area)
    println(s2.area)
    println(s3.area)
  }
}

4、抽象字段

在scala中,也可以定義抽象的字段。如果一個成員變量是沒有初始化,我們就認爲它是抽象的。

定義

語法

abstract class 抽象類 {
    val/var 抽象字段:類型
}

示例

示例說明
1.	創建一個Person抽象類,它有一個String抽象字段WHO_AM_I
2.	創建一個Student類,繼承自Person類,重寫WHO_AM_I字段,初始化爲學生
3.	創建一個Policeman類,繼承自Person類,重寫WHO_AM_I字段,初始化警察
4.	添加main方法,分別創建Student/Policeman的實例,然後分別打印WHO_AM_I

參考代碼

// 定義一個人的抽象類
abstract class Person6 {
  // 沒有初始化的val字段就是抽象字段
  val WHO_AM_I:String
}

class Student6 extends Person6 {
  override val WHO_AM_I: String = "學生"
}

class Policeman6 extends Person6 {
  override val WHO_AM_I: String = "警察"
}

object Main6 {
  def main(args: Array[String]): Unit = {
    val p1 = new Student6
    val p2 = new Policeman6

    println(p1.WHO_AM_I)
    println(p2.WHO_AM_I)
  }
}

5、匿名內部類

匿名內部類是沒有名稱的子類,直接用來創建實例對象。Spark的源代碼中有大量使用到匿名內部類。
scala中的匿名內部類使用與Java一致。

定義
語法

val/var 變量名 = new 類/抽象類 {
    // 重寫方法
}

示例

示例說明
1.	創建一個Person抽象類,並添加一個sayHello抽象方法
2.	添加main方法,通過創建匿名內部類的方式來實現Person
3.	調用匿名內部類對象的sayHello方法

參考代碼

abstract class Person7 {
  def sayHello:Unit
}

object Main7 {
  def main(args: Array[String]): Unit = {
    // 直接用new來創建一個匿名內部類對象
    val p1 = new Person7 {
      override def sayHello: Unit = println("我是一個匿名內部類")
    }
    p1.sayHello
  }
}

6、特質(trait)

scala中沒有Java中的接口(interface),替代的概念是——特質

定義

•	特質是scala中代碼複用的基礎單元
•	它可以將方法和字段定義封裝起來,然後添加到類中
•	與類繼承不一樣的是,類繼承要求每個類都只能繼承一個超類,而一個類可以添加任意數量的特質。
•	特質的定義和抽象類的定義很像,但它是使用trait關鍵字

語法

定義特質
trait 名稱 {
    // 抽象字段
    // 抽象方法
}
繼承特質
class 類 extends 特質1 with 特質2 {
    // 字段實現
    // 方法實現
}
•	使用extends來繼承trait(scala不論是類還是特質,都是使用extends關鍵字)
•	如果要繼承多個trait,則使用with關鍵字

7、trait作爲接口使用

trait作爲接口使用,與java的接口使用方法一樣。
示例 | 繼承單個trait

示例說明
1.	創建一個Logger特質,添加一個接受一個String類型參數的log抽象方法
2.	創建一個ConsoleLogger類,繼承Logger特質,實現log方法,打印消息
3.	添加main方法,創建ConsoleLogger對象,調用log方法

參考代碼

  trait Logger {
    // 抽象方法
    def log(message:String)
  }

  class ConsoleLogger extends Logger {
    override def log(message: String): Unit = println("控制檯日誌:" + message)
  }

  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.log("這是一條日誌")
  }
示例 | 繼承多個trait

示例說明
1.	創建一個MessageSender特質,添加send方法
2.	創建一個MessageReceiver特質,添加receive方法
3.	創建一個MessageWorker實現這兩個特質
4.	在main中調用,分別調用send方法、receive方法

參考代碼

trait MessageSender {
    def send(msg:String)
}

trait MessageReceive {
    def receive():String
}

class MessageWorker extends MessageSender with MessageReceive {
    override def send(msg: String): Unit = println(s"發送消息:${msg}")

    override def receive(): String = "你好!我叫一個好人!"
}

def main(args: Array[String]): Unit = {
    val worker = new MessageWorker
    worker.send("hello")
    println(worker.receive())
}
示例 | object繼承trait

示例說明
1.	創建一個Logger特質,添加一個log抽象方法
2.	創建一個ConsoleLogger的object,實現LoggerForObject特質,實現log方法,打印消息
3.	編寫main方法,調用ConsoleLogger的log方法

參考代碼

trait Logger {
    def log(message:String)
}

object ConsoleLogger extends Logger {
    override def log(message: String): Unit = println("控制檯消息:" + message)
}

def main(args: Array[String]): Unit = {
    ConsoleLogger.log("程序退出!")
}

8、特質 | 定義具體的方法

和類一樣,trait中還可以定義具體的方法

示例

示例說明
1.	定義一個Logger特質,添加log實現方法
2.	定義一個UserService類,實現Logger特質
	添加add方法,打印"添加用戶"
3. 添加main方法
	創建UserService對象實例
	調用add方法

參考代碼

trait LoggerDetail {
  // 在trait中定義具體方法
  def log(msg:String) = println(msg)
}

class UserService extends LoggerDetail {
  def add() = log("添加用戶")
}

object MethodInTrait {
  def main(args: Array[String]): Unit = {
    val userService = new UserService
    userService.add()
  }
}

9、trait中定義具體的字段和抽象的字段

定義

	在trait中可以定義具體字段和抽象字段
	繼承trait的子類自動擁有trait中定義的字段
	字段直接被添加到子類中

示例

示例說明
通過trait來實現一個日誌輸出工具,該日誌工具可以自動添加日誌的日期

步驟

1.	創建Logger特質
	定義一個SimpleDateFormat字段,用來格式化日期(顯示到時間)
	定義一個TYPE抽象字段,用於定義輸出的信息
	創建一個log抽象方法,用於輸出日誌
2.	創建ConsoleLogger類,實現TYPE抽象字段和log方法
3.	添加main方法
	創建ConsoleLogger類對象
	調用log方法

參考代碼

  trait Logger {
    val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm")
    def log(msg:String)
  }

  class ConsoleLogger extends Logger {
    override def log(msg: String): Unit = {
      val info = s"${sdf.format(new Date())}:控制檯消息:${msg}"
      println(info)
    }
  }

  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger()
    logger.log("NullPointerException")
  }

10、使用trait實現模板模式

要實現以下需求:
	實現一個輸出日誌的功能
	目前要求輸出到控制檯
	將來可能會輸出到文件、輸出到Redis、或者更多的需求
如何實現將來不修改之前的代碼,來擴展現有功能呢?

在這裏插入圖片描述

定義

在一個特質中,具體方法依賴於抽象方法,而抽象方法可以放到繼承trait的子類中實現,這種設計方式也稱爲模板模式

在這裏插入圖片描述

在scala中,trait是可以定義抽象方法,也可以定義具體方法的
	trait中定義了一個抽象方法
	trait中定義了其他的幾個具體方法,會調用抽象方法
	其他實現類可以來實現抽象方法
	真正調用trait中具體方法的時候,其實會調用實現類的抽象方法實現

示例

示例說明
	編寫一個日誌輸出工具,分別有info、warn、error三個級別的日誌輸出
	日誌輸出的方式要求設計爲可擴展的,例如:可以輸出到控制檯、將來也可以擴展輸出到文件、數據庫等

實現步驟

1.	添加一個Logger特質
	添加一個log抽象方法
	添加一個info、warn、error具體方法,這幾個方法調用log抽象方法
2.	創建ConsoleLogger類,實現Logger特質
3.	添加main方法
	創建ConsoleLogger類對象
	分別調用info、warn、error方法輸出日誌

參考代碼

  trait Logger {
    def log(msg:String)
    def info(msg:String) = log("INFO:" + msg)
    def warn(msg:String) = log("WARN:" + msg)
    def error(msg:String) = log("ERROR:" + msg)
  }

  class ConsoleLogger extends Logger {
    override def log(msg: String): Unit = {
      println(msg)
    }
  }

  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.info("信息日誌")
    logger.warn("警告日誌")
    logger.error("錯誤日誌")
  }

11、對象混入trait

scala中可以將trait混入到對象中,就是將trait中定義的方法、字段添加到一個對象中

定義

語法

val/var 對象名 = new 類 with 特質

示例

•	給一個對象添加一些額外的行爲

步驟

1.	創建一個Logger特質
	添加一個log實現方法,打印參數
2.	創建一個UserService類
3.	添加main方法
	創建UserService對象,混入Logger特質
	調用log方法

參考代碼

  trait Logger {
    def log(msg:String) = println(msg)
  }

  class UserService

  def main(args: Array[String]): Unit = {
    val service = new UserService with Logger
    service.log("混入的方法")
  }

12、trait實現調用鏈模式

我們如果要開發一個支付功能,往往需要執行一系列的驗證才能完成支付。例如:
1.	進行支付簽名校驗
2.	數據合法性校驗
3.	...
如果將來因爲第三方接口支付的調整,需要增加更多的校驗規則,此時如何不修改之前的校驗代碼,來實現擴展呢?
責任鏈模式

在這裏插入圖片描述

trait調用鏈

在這裏插入圖片描述

類繼承了多個trait後,可以依次調用多個trait中的同一個方法,只要讓多個trait中的同一個方法在最後都依次執行super關鍵字即可。類中調用多個tait中都有這個方法時,首先會從最右邊的trait方法開始執行,然後依次往左執行,形成一個調用鏈條。

示例

實現一個模擬支付過程的調用鏈

在這裏插入圖片描述

步驟

1.	定義一個HandlerTrait特質
	定義一個具體的handler方法,打印"處理數據..."
2.	定義一個DataValidHandlerTrait,繼承HandlerTrait特質
	重寫handler方法,打印"驗證數據"
	調用父特質的handler方法
3.	定義一個SignatureValidHandlerTrait,繼承HandlerTrait特質
	重寫Handler方法
	打印"檢查簽名"
	調用父特質的handler方法
4.	創建一個PaymentService類
	繼承DataValidHandlerTrait
	繼承SignatureValidHandlerTrait
	定義pay方法
	打印"準備支付"
	調用父特質的handler方法
5.	添加main方法
	創建PaymentService對象實例
	調用pay方法

參考代碼

trait HandlerTrait {
   def handle(data:String) = println("處理數據...")
}

trait DataValidHanlderTrait extends HandlerTrait {
   override def handle(data:String): Unit = {
       println("驗證數據...")
       super.handle(data)
  }
}

trait SignatureValidHandlerTrait extends HandlerTrait {
   override def handle(data: String): Unit = {
       println("校驗簽名...")
       super.handle(data)
  }
}

class PayService extends DataValidHanlderTrait with SignatureValidHandlerTrait {
   override def handle(data: String): Unit = {
       println("準備支付...")
       super.handle(data)
  }
}

def main(args: Array[String]): Unit = {
   val service = new PayService
   service.handle("支付參數")
}
// 程序運行輸出如下:
// 準備支付...
// 檢查簽名...
// 驗證數據...
// 處理數據...

trait繼承class
定義
trait也可以繼承class的。特質會將class中的成員都繼承下來。
示例
示例說明
 定義一個特質,繼承自一個class
步驟

  1. 創建一個MyUtils類,定義printMsg方法
  2. 創建一個Logger特質,繼承自MyUtils,定義log方法
  3. 創建一個Person類,添加name字段
     繼承Logger特質
     實現sayHello方法,調用log方法
  4. 添加main方法,創建一個Person對象,調用sayHello方法

參考代碼

class MyUtil {
   def printMsg(msg:String) = println(msg)
}

trait Logger extends MyUtil {
   def log(msg:String) = printMsg("Logger:" + msg)
}

class Person extends Logger {
   def sayHello() = log("你好")
}

def main(args: Array[String]): Unit = {
   val person = new Person
   person.sayHello()
}

scala操作就到這,內容很多,想要學好spark的小夥伴們一定要認真的把scala學好,下一階段給大家更新spark內容哦!!!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章