scala物件導向

半度、發表於2020-10-30

Scala物件導向程式設計

1.課程目標

  • 掌握Scala中物件導向程式設計
  • 掌握Scala模式匹配
  • 掌握Scala泛型高階內容
  • 熟悉Scala中多執行緒程式設計模型

2.物件導向

2.1 類

  • 定義: class 類名{
        	成員變數
        	val/var 名稱=值
        	成員方法
        	def 方法名稱(引數列表):返回值={
                方法體
            }
    	}
    建立物件:
    	val 物件名稱=new 類名() //() 可寫可不寫  ()沒有引數的時候可以省略
    
    /**
      * Person
      * name 不可變
      * age  可變
      * skill 陣列
      * 方法:
      * def addSkill
      * def scanSkill
      */
    class Person {
      val name = "itcast"  //不可變 不需要setter 
      var age = 13  //可變 需要setter getter
      val skill = new ArrayBuffer[String]()
    
      // def addSkill
      def addSkill(subject: String): Unit = {
        skill += subject
      }
    
      def scanSkill(): Unit = {
        skill.foreach((x: String) => println(x))
      }
    }
    
    
    object Scala_01_class {
      def main(args: Array[String]): Unit = {
        val person = new Person
        println(person.name)
        person.age=14
        println(person.age)
        person.addSkill("scala")
        person.addSkill("spark")
        person.scanSkill()
      }
    }
    

2.2 setter getter

  • /**
      * Student類
      * name 不可變
      * age 可變
      *
      * 注意:
      *   1.如果一個方法 只返回結果 在方法內部不進行任何業務邏輯處理的話,就可以省略方法名稱後邊的小括號“()”
      *   2.通過def 定義屬性
      */
    
    class Student {
      val name = "itcast" //不需要提供setter 和getter
      private var _age = 10 //可變變數定義格式 : _名稱
      //setter
      def age_(age: Int) = this._age = age
    
      //getter
      def  age=this._age
    }
    
    object Scala_02_class {
      def main(args: Array[String]): Unit = {
        val student = new Student
        student.age_(10)
        println(student.age)
      }
    }
    

2.3 方法的呼叫原則

  • /**
      * Teacher 類
      *   teach方法
      *
      *   注意:teacher teach "spark" 這種呼叫方式只適用於一個引數的方法
      */
    class Teacher{
      def teach(suject:String): Unit ={
        println(s"教學:$suject")
      }
    }
    
    object Scala_03_class {
      def main(args: Array[String]): Unit = {
        val teacher = new Teacher
        teacher.teach("hadoop")
        teacher teach("scala")
        teacher teach "spark"
        0 to 10 
        0 until 10
        1 + 2
      }
    }
    

2.4 Scala構造器

  • 兩種構造器方式
    	主構造器
    		class 類名(引數*)
    	輔助構造器
    		定義在類當中
    		def this(引數*){
                //第一行程式碼必須代用主構造
                this(引數)
            }
    /**
      * 定義: Animal
      * 主構造器 (name)
      * 輔助構造(color,legs)
      */
    class Animal(val name: String) {
      var _color = "red"
      var _legs = 2
    
      //輔助構造(name,color,legs)
      def this(name: String, color: String, legs: Int) {
        this(name) //呼叫主構造器
        this._color = color
        this._legs = legs
      }
    }
    
    object Scala_04_class {
      def main(args: Array[String]): Unit = {
        val a=new Animal("dog")
    
        val b=new Animal("cat","white",2)
    
        println(a.name)
        println(b._legs)
      }
    }
    

2.5 Scala中單例物件

  • 建立方式:
    	object 名稱{
            成員變數
            成員方法
        }
    使用方式:
    	可以通過 名稱.成員變數/成員方法 形式使用。相當於java中static修飾變數和方法的呼叫
     應用場景:
    	單例物件多應用於工具類或者工具物件
    //建立工具物件
    object CommonUtil {
      val PI = 3.14
    
      def getDate = new Date
    }
    
    object Scala_05_object {
      def main(args: Array[String]): Unit = {
        println(CommonUtil.PI)
        println(CommonUtil.getDate)
      }
    }
    

2.6 伴生物件

  • 當單例物件的名稱跟類名相同的時候,並且單例物件和類同時存在於同一個檔案中, 這裡這個物件就稱之為類的伴生物件。類是物件的伴生類
    
    /**
      * SoftEngineer 類
      * SoftEngineer  object
      * 1.伴生類和伴生物件之間可以互相訪問 private屬性和方法
      * 2.apply存於伴生物件中 能夠實現伴生類建立物件的功能 ,相當於java中的工廠模式的定義
      */
    class SoftEngineer(val exp:Int){
      private var salary=1000
      def getHasGF()={
        SoftEngineer.hasGF //訪問伴生物件中私有變數
      }
      val hasHair=SoftEngineer.hasHair()
    
    }
    
    object SoftEngineer{
      private var hasGF=false
      //定義方法 訪問伴生類的私有變數
      def getSalary()={
        val engineer = new SoftEngineer(10)
        engineer.salary  //訪問私有變數
      }
      private def hasHair()={
        true
      }
    
      def apply(exp:Int): SoftEngineer = new SoftEngineer(exp)
    }
    
    
    object Scala_06_object {
      def main(args: Array[String]): Unit = {
        val engineer = new  SoftEngineer(10)
        println(engineer.getHasGF())
        println(engineer.hasHair)
        println( SoftEngineer.getSalary())
    
        val engineer2 = SoftEngineer(10) //Array(“dd”) List("ddd")
      }
    }
    

2.7 main函式

  • //通過繼承App的方式可以省略掉main 
    //本質上 還是沒有省略 App中包含main函式
    object Scala_07_object extends App {
      println("hello app")
      println(args(0))
    }
    

2.8 繼承

  • 格式:class 類名 extends 父類
    1.scala單繼承
    2.子類可以繼承父類的非私有的屬性和方法
    3.子類可以重寫父類的方法和屬性
    4.子類可以通過super關鍵詞呼叫父類的屬性和方法
    
    /**
      * 父類  BigDataEngineer
      *   不可變 name
      *   可變 age
      *   方法 study
      * 子類  HadoopEngineer
      *
      */
    class BigDataEngineer{
      val  name="BigData"
      var age=10
      def study():Unit={
        println("學習和開發")
      }
    }
    class HadoopEngineer extends BigDataEngineer{
      //子類覆蓋父類中的study方法  override
      override def study(): Unit = {
        age=12
        super.study()
        println("開發hadoop")
      }
    }
    object Scala_08_extends extends App{
         val engineer = new HadoopEngineer
         println(engineer.name)
         engineer.study()
    }
    問題:子類在建立物件的時候,是否呼叫了父類的構造器? 
    	scala中子類建立物件的時候也同樣呼叫了父類的構造器
    
    
  • Scala中構造機制

    • /**
        * 類 Person_09
        * 子類 Sun_09
        */
      class Person_09{
        println("Person_09")  //主構造器呼叫完成之後直接呼叫
      }
      
      class Sun_09 extends  Person_09{
        println("Sun_09")
      }
      
      object Scala_09_extends extends  App {
         val sun_0 = new Sun_09
         //根據列印結果
          //在子類建立物件的過程中,呼叫了父類的構造器的
      }
      

2.9 子類呼叫父類的構造器

  • 子類主構造器沒有引數,父類主構造器有引數
    子類主構造器有引數,父類主構造器也有引數
    
    /**
      * 父類PC 電腦(cup memory)
      *   子類 NotePC
      *    桌上型電腦:DeskPC(cup memory)
      */
    class PC(val cpu:Int,val memory:Int)
    
    class NotePC extends PC(cpu = 10,memory = 20)
    
    class DeskPC(cpu:Int,memory:Int) extends PC(cpu,memory)
    
    object Scala_10_extends {
      def main(args: Array[String]): Unit = {
        val n = new NotePC
        println(n.cpu)
        println(n.memory)
        println("----------------------")
        val deskPC=new DeskPC(30,60)
        println(deskPC.cpu)
        println(deskPC.memory)
      }
    }
    

2.10 抽象類

  • 定義: abstract class 類名
    1.可以定義抽象方法和抽象屬性(沒有初始化的屬性)
    2.可以有非抽象的方法和非抽象屬性
    3.如果方法或者屬性被final修飾,不能夠被重寫
    
    /**
      * Employee 員工
      * val name 抽象
      * var age 非抽象的
      * 抽象方法 work
      * 非抽象方法 study
      * final 方法:sleep
      */
    abstract class Employee {
      val name: String //抽象屬性 資料型別不能夠省略
      var age = 25
    
      def work(): Unit //抽象方法返回值型別不能夠省略
      def study(): Unit = {
        println("學習公司文化")
      }
    
      final def sleep(): Unit = {
        println("休息")
      }
    }
    
    class ScalaEmployee extends Employee {
      /**
        * override  如果覆蓋的是非抽象的方法或者屬性 這裡不能夠省略
        * 如果覆蓋的是抽象方法或者屬性 這裡可以省略
        */
      override val name: String = "scala"
    
      override def work(): Unit = {
        println("開發scala應用程式")
      }
    
    }
    
    object Scala_11_extends extends App {
      private val employee = new ScalaEmployee
      println(employee.name)
      employee.work()
      employee.study()
    }
    

2.11匿名內部類

  • 應用場景:
    	ScalaProgramer  只會開發scala應用程式。python 
    
    class ScalaProgrammer {
      def workerByScala(): Unit = {
        println("開發scala應用程式")
      }
    }
    class pyAndScaProgrammer extends ScalaProgrammer{
        def workerByPython(): Unit = {
            println("學習並開發python")
          }
    }
    object Scala_12_innerclass {
      def main(args: Array[String]): Unit = {
        //python專案 臨時性需求
       val scala= new ScalaProgrammer {
          def workerByPython(): Unit = {
            println("學習並開發python")
          }
        }
        scala.workerByPython()
        scala.workerByScala()
        println(scala.getClass)
      }
    }
    

2.12 超級父類

  • Any 超級分類
    	AnyRef  所有引用型別物件的超級父類 ScalaProgrammer
    	AnyVal  所有值型別物件的超級父類 Int Double...
    

2.13 型別轉換和型別判斷

  • 子類繼承父類,父類的引用可以指向子類物件。父類的引用是多型的。多型的問題 :型別轉換異常
    
    *  val worker = w.asInstanceOf[Worker]
    	1. 物件.isInstanceOf[型別]  模糊判斷 不精準
          * 2. 物件.getClass=classOf[型別]
    class Worker {
      def work(): Unit = {
        println("工作")
      }
    }
    
    class JavaWorker extends Worker {
      def workByJava(): Unit = {
        println("開發java專案")
      }
    }
    
    object Scala_13_change {
      def boss(w: Any): Unit = {
        //將any物件轉換成 worker物件
        //判斷物件的型別
        /**
          * 1. 物件.isInstanceOf[型別]  模糊判斷 不精準
          * 2. 物件.getClass=classOf[型別]
          */
        if (w.isInstanceOf[Worker]) {
          val worker = w.asInstanceOf[Worker]
          worker.work()
        } else {
          println("回家等訊息")
        }
      }
    
      def boss2(w: Any): Unit = {
        //將any物件轉換成 worker物件
        //判斷物件的型別
        /**
          * 1. 物件.isInstanceOf[型別]  模糊判斷 不精準
          * 2. 物件.getClass=classOf[型別]
          */
        if (w.getClass()==classOf[JavaWorker]) {
          val worker = w.asInstanceOf[JavaWorker]
          worker.workByJava()
        } else {
          println("回家等訊息")
        }
      }
    
      def main(args: Array[String]): Unit = {
        val worker = new Worker
        /*boss(worker)
        boss(new Student)*/
        val javaWorker = new JavaWorker
        boss2(worker)
      }
    }
    

2.14特質

  • 特質的功能

    • 格式:trait 名稱
    • 功能:
      • 特質可以作為java中的介面使用
      • 特質可以作為抽象類使用
      • 特質可以擴充套件物件的方法(1 個方法 --》多個方法)
      • 特質可以擴充套件特定方法的功能
  • 特質作為介面使用

    • /**
        * 定義
        * trait  名稱
        * 可以作為介面使用
        *   1.可以定抽象方法
        *   2.介面可以多實現
        */
      格式:類 extends Tarit名稱 with  Tarit名稱2 with Tarit名稱3
      
      trait HelloTrait {
        def sayHellByChina(): Unit
      }
      
      trait HelloTraitHanguo {
        def sayHellByHanguo(): Unit
      }
      
      trait HelloTraitTaiguo {
        def sayHellByTaiguo(): Unit
      }
      
      class HelloTraitImpl extends HelloTrait with HelloTraitHanguo with HelloTraitTaiguo {
        override def sayHellByChina(): Unit = {
          println("你好")
        }
      
        override def sayHellByHanguo(): Unit = {
          println("阿尼哈沙有")
        }
      
        override def sayHellByTaiguo(): Unit = {
          println("薩瓦迪卡")
        }
      }
      
      object Scala_14_trait {
        def main(args: Array[String]): Unit = {
          val impl = new HelloTraitImpl
          impl.sayHellByChina()
          impl.sayHellByHanguo()
          impl.sayHellByTaiguo()
        }
      }
      
  • 特質作為抽象類使用

    • trait AbstractTrait {
        //非抽象屬性和方法
        val name = "itcast"
      
        def study(): Unit = {
          println("學習")
        }
      
        //抽象屬性和方法
        val age: Int
      
        def work(): Unit
      
      }
      
      class AbstractTraitImpl extends AbstractTrait {
        override val age: Int = 10
      
        override def work(): Unit = {
          println("工作")
        }
      }
      
      object Scala_15_trait extends App {
        private val impl = new AbstractTraitImpl
        println(impl.age)
        println(impl.name)
        impl.work()
        impl.study()
      }
      特質和抽象類的區別
      	1.抽象類可以有自己的主構造器以及初始化引數
          2.特質可以多實現但是抽象類只能進行單繼承或者多重繼承
      
  • 特質擴充套件物件的功能

    • package cn.itcast.day02
      
      class Tank {
        def shoot(): Unit = {
          println("發射子彈")
        }
      }
      
      trait Aim {
        def aim(): Unit = {
          println("瞄準")
        }
      }
      
      trait Scan {
        def scan(): Unit = {
          println("掃描")
        }
      }
      
      trait Fly{
        def fly():Unit
      }
      
      object Scala_16_trait {
        def main(args: Array[String]): Unit = {
          val tank = new Tank with Aim with Scan with Fly{
            override def fly(): Unit = {
              println("飛上天")
            }
          }
          tank.scan()
          tank.aim()
          tank.shoot()
          tank.fly()
        }
      }
      
  • 特質擴充套件特定方法的功能

    • super: 線性呼叫的標誌符,線性是動態過程 是根據特質的混入順序有關的
      線性執行順序:自右向左的過程
      
      class Tank2 {
        def shoot(): Unit = {
          println("發射")
        }
      }
      
      trait Aim2 extends Tank2 {
        override def shoot(): Unit = {
      
          println("瞄準")
          super.shoot()
        }
      }
      
      trait Scan2 extends Tank2 {
        override def shoot(): Unit = {
          println("掃描")
          super.shoot()
        }
      }
      class SuperTank extends Tank2 with Aim2 with Scan2
      
      object Scala_17_trait {
        def main(args: Array[String]): Unit = {
          val tank = new SuperTank
          tank.shoot()
        }
      }
      
  • 特質構造機制

    • 構造機制的執行原則:  從左往右  自上而下
      
      trait T0{
        println(0)
      }
      trait T1{
        println(1)
      }
      trait T2{
        println(2)
      }
      trait T3 extends T1{
        println(3)
      }
      class Timpl extends T0 with T3 with  T2 with  T1{
        println("Timpl")
      }
      
      object Scala_18_trait extends App {
        //1 2 1 3 0
        // Timpl  1 2 1 3 0
        new Timpl  // 從左往右  自上而下
      }
      

3. 模式匹配

  • 功能類似於java中switch結構,但是要比swith強大的多

    • 數值
    • 資料型別
    • Array
    • List
    • Tuple
    • Map
    • 自定義資料型別
  • 結構:
    	value match {
            case 需要匹配值或者型別 =>{ 執行邏輯}
            case _ => {執行邏輯} //預設的匹配
        }
    
  • 模式匹配值匹配

    • //值匹配
      val arr = Array("hadoop", "scala", "spark")
      var value = arr((math.random * arr.size).toInt)
      //println("value:" + value)
      value="java"
      
      /**
        * value match {
        * case 需要匹配值或者型別 =>{ 執行邏輯}
        * case _ => {執行邏輯} //預設的匹配
        * }
        */
      value match {
        case "hadoop" => println("匹配Hadoop")
        case "scala" => println("匹配scala")
        case "spark" => println("匹配spark")
        case _ =>println("預設匹配")
      }
      
  • 資料型別匹配

    • object DataType {
        def main(args: Array[String]): Unit = {
          val arr=Array("hadoop",1.34,10,true)
          var value = arr((math.random * arr.size).toInt)
          println("value:"+value)
          value match {
            case s:String => println(s+"-------------")
            case d:Double => println(d+"-------------")
            case i:Int => println(i+"-------------")
            case b:Boolean =>println(b+"-------------------")
          }
        }
      }
      
  • 模式匹配陣列

    • object MatchArray{
        def main(args: Array[String]): Unit = {
          val arr=Array("hadoop",1.34,10,true)
          arr match {
             //能否有個配所有array
            
            //非精確匹配
            case Array("hadoop1",_*) =>println("333333")
            //佔位符匹配
            case Array("hadoop",1.34,_,_) =>println("222222222")
             //精確匹配
            case Array("hadoop",1.34,10,true) =>println("111111")
              case Array(_*) =>println("4444444")
          }
        }
      }
      
  • 模式匹配列表

    • object MatchList{
        def main(args: Array[String]): Unit = {
          val list=List("hadoop","spark","scala")
          list match {
            case "hadoop"::"spark"::"scala"::Nil =>println("sfsfsfdsfsdsdfd")
             //模糊匹配
            case List(x,_*) =>println(x)
            case List(x,y,_) =>println(x+"\t"+y)
            //精確匹配
            case List(x,y,z) =>println(x+"\t"+y+"\t"+z)
            case List("hadoop","spark","scala") => println("精確匹配list")
          }
        }
      }
      
  • 模式匹配Tuple

    • object MatchTuple {
        def main(args: Array[String]): Unit = {
          val t = ("hadoop", 1.23, 10, true)
      
          t match {
            case (x,_,_,_) =>println("sdfdsfds")
            case _ =>println("預設匹配。。。。")
            //case ("hadoop",_*) =>println("")
            case ("hadoop",_,_,_) =>println("匹配佔位符tuple")
            case  ("hadoop", 1.23, 10, true) =>println("精確匹配tuple")
          }
      
        }
      }
      
  • 模式匹配Map

    • object  MatchMap{
        def main(args: Array[String]): Unit = {
          val map=Map("hadoop"->100,"scala"->50)
          val value=map.get("java")
          value match  {
            case Some(x) =>println(x)
            case None =>println("沒有值")
          }
        }
      }
      
  • 模式匹配自定資料型別

    • 樣例類 case class 名稱

      • 樣例類跟普通類區別:樣例類能夠自動構建apply方法
    • 樣例物件

      • case object 名稱 :應用場景 只是作為標誌
    • case class Task(name: String)
      case object TaskObject
      
      object MatchCaseClass {
        def main(args: Array[String]): Unit = {
          val arr = Array(Task("itcast"), TaskObject)
          val value = arr((math.random * arr.size).toInt)
          println("value:" + value)
          Task("lisi") match {
            case Task(name) => println("name:" + name)
            case TaskObject => println("匹配樣例物件")
          }
        }
      }
      

4. 偏函式 x=>y

  • 把模式匹配這種形式 放在一個方法或者一個函式中,就構成一種新的函式,偏函式
    //方法
    def 名稱(引數)= value math{
        case 操作
    }
    //函式
    val 名稱:PartialFunction[輸入資料型別,返回值資料型別] ={
        case 操作
    }
    
    object Scala_20_pianhanshu {
    
      def intMatch(x: Int) = x match {
        case 10 => println("10")
        case 100 => 100
      }
     
      def main(args: Array[String]): Unit = {
        intMatch(10)
        println(intMatch(100))
    
        val matchFuncion: PartialFunction[Int, String] = {
          case x:Int => x + " is even"
        }
        println(matchFuncion(10))
      }
    }
    
    

5.逆變協變非變

  • class Apple
    class RedApple  extends Apple
    class Box[T]
    問題:RedApple 是 Apple 子類, Box[RedApple] 是不是 Box[Apple]子類? 假如  Box[RedApple] 是 Box[Apple]子類
     val box:Box[Apple] =new Box[RedApple] 則成立 ,反之則不成立  
    答案 :以上假設不成立
    
    要想讓以上操作成立 需要協變操作
    
    
    
    
    RedApple extends Apple
    class Box[T]  
    a=Box[Apple]  b=Box[RedApple]
    
    
    class Box[+T]  
    a=Box[Apple]  b=Box[RedApple]
    
    class Box[-T]  
    a=Box[Apple]  b=Box[RedApple]
    逆變:class Box[-T]  
    	val box:Box[RedApple] =new Box[Apple] 
    
    
    class RedApple extends Apple
    
    class Box[+T]  //協變
    
    class Box2[-T]
    
    object Scala_21_fanxin {
      def main(args: Array[String]): Unit = {
        val box: Box[Apple] = new Box[RedApple]
    
        val box2:Box2[RedApple] =new Box2[Apple]
      }
    }
    Son extends Person
    
    總結:a=ArrayList<Person> b=ArrayList<Son>
        
    C[T]:	A是B的子類 C[A]與C[B]之間沒有任何關係  非變操作
    C[+T]: A是B的子類  C[A]是C[B]的子類  協變操作
    C[-T]: A是B的子類  C[A]是C[B]的父類  逆變操作
    

6.上下界

  • 上下界 影響的是方法的入參
    
    U>:Class U 帶表的class本身以及其父類 下界操作 下界限制不住
    U<:Class U 代表class 本身以及其子類  上界操作
    
    class OldMan extends Man
    
    class  OldOldMan extends  OldMan
    
    class YoungMan extends Man
    
    class ChildMan extends YoungMan
    
    class Sport {
      //新增下界操作 U 代表的是 OldMan 本身 或者是其父類  下界操作 其實是無下界
      def guangchangwu[U >: OldMan](man: U): Unit = {
        println("廣場舞")
      }
      //U 帶表示 YoungMan本身以及其子類
      def qiaodaima[U<:YoungMan](man: U): Unit = {
        println("敲程式碼")
      }
    }
    
    object Scala_22_upanddown {
      def main(args: Array[String]): Unit = {
        val sport = new Sport
        val yman = new YoungMan
        val oman = new OldMan
        val ooman=new OldOldMan
        val cman = new ChildMan
     /*   sport.guangchangwu(yman)
        sport.guangchangwu(oman)
        sport.guangchangwu(ooman)*/
    
        sport.qiaodaima(cman)
    
      }
    }
    
    

7.Scala併發操作

  • 格式:	
    	class 執行緒類 extends Actor{
            def act()
        }
    //啟動執行緒
    	actor.start()
    
    /**
      * 建立執行緒類 MyActor
      */
    class MyActor(val name: String) extends Actor {
      override def act(): Unit = {
        for (i <- 0 to 10) {
          println(name + ":" + i)
        }
      }
    }
    
    object Scala_23_actor {
      def main(args: Array[String]): Unit = {
        val itcast = new MyActor("itcast")
        val tian = new MyActor("Tian")
        itcast.start()
        tian.start()
      }
    }
    
  • Actor基於訊息機制的併發

    • actor能夠傳送訊息 和接受訊息,根據訊息的不同,去執行不同的業務邏輯

    • ! 傳送訊息

    • class MyActor2 extends Actor {
        override def act(): Unit = {
          var flag = true
          while (flag)
            receive { //阻塞
              case "start" => println("啟動成功") //執行邏輯完成後自動退出
              case "test" => println("測試")
              case "end" => {
                println("退出")
                flag = false
              }
            }
        }
      }
      
      object Scala_24_actor {
        def main(args: Array[String]): Unit = {
          val actor = new MyActor2()
          actor.start()
          actor ! "start"
          actor!"test"
          actor ! "end"
        }
      }
      
  • loop react

    • class MyActor2 extends Actor {
        override def act(): Unit = {
          loop{
            react{
              case "start"=>println("啟動成功過")
              case "test" =>println("測試")
              case "end"=> exit()
            }
          }
        }
      }
      
      object Scala_24_actor {
        def main(args: Array[String]): Unit = {
          val actor = new MyActor2()
          actor.start()
          actor ! "start"
          actor!"test"
          actor ! "end"
        }
      }
      
  • Actor傳送訊息的三種方式

    • ! 非同步訊息 並且無返回值

    • !? 同步訊息 有返回值

    • !! 非同步訊息 有返回值 Future[Any]

    • 同步訊息和非同步訊息

      • 同步訊息:傳送訊息後,會等待訊息執行邏輯完成,再返回
      • 非同步訊息:傳送訊息後直接返回,返回會在將來的某一時刻返回 Future[Any]
    • 總和案例:

      • 結合樣例類方式 來整同步訊息和非同步訊息以及返回值
      • 需要構建3個樣例類
    • /**
        * 訊息模型
        * 同步訊息
        * 非同步訊息
        * 返回值訊息
        */
      case class SynMsg(msg: String, time: Long)
      
      case class AsynMsg(msg: String, time: Long)
      
      case class ReplayMsg(msg: String)
      
      class MsgActor extends Actor {
        override def act(): Unit = {
          loop {
            react {
              case SynMsg(msg, time) => {
                Thread.sleep(time)
                println(msg)
                sender ! ReplayMsg(msg + "---SynMsg-----")
              }
              case AsynMsg(msg, time) => {
                Thread.sleep(time)
                println(msg)
                sender ! ReplayMsg(msg + "---AsynMsg-----")
              }
            }
          }
        }
      }
      
      object Scala_25_actor {
        def main(args: Array[String]): Unit = {
          val actor = new MsgActor
          actor.start()
          /*val msg1=actor!?SynMsg("itcast",5000)
          val msg2=actor!?SynMsg("itcast2",1000)
           println(msg1)
           println(msg2)*/
      
          val msg1 = actor !! AsynMsg("itcast", 5000)
          val msg2 = actor !! AsynMsg("itcast2", 1000)
      
          val list = ListBuffer[Future[Any]]()
          list += msg1
          list += msg2
      
          while (list.size > 0) {
            for (msg <- list) { //msg:Future[Any]
              //判斷future是否接收到資料
              if (msg.isSet) { //ture 代表已經接受到資料
                val replayMsg = msg.apply().asInstanceOf[ReplayMsg]
                println(replayMsg.msg)
                list -= msg
              }
            }
          }
        }
      }
      
  • 基於Actor的wordcount案例

    • 操作步驟:

      • 準備檔案 a.txt b.txt c.txt
      • 構建actor
      • 通過樣例類 構建訊息的載體 case FilePathMsg(path:String)
      • actor接受訊息 並且處理檔案資料
      • 接受返回值 並且將返回值放在ListBuffer進行管理
      • 對ListBuffer進行迴圈操作,拿到檔案處理資料,把檔案處理資料放在一個集合中
      • 對集合進行彙總處理
    • package cn.itcast.day02
      
      import java.io.File
      
      import scala.actors.{Actor, Future}
      import scala.collection.mutable.{ArrayBuffer, ListBuffer}
      import scala.io.Source
      
      /**
        * 樣例類方式構建訊息載體
        */
      case class FilePathMsg(path: String)
      
      //返回值訊息
      case class FileResultMsg(result: Map[String, Int])
      
      class FileActor extends Actor {
        override def act(): Unit = {
          loop {
            react {
              case FilePathMsg(path) => {
                //讀取檔案資料 並且進行處理 Map
                val map: Map[String, Int] = Source.fromFile(new File(path)).getLines().mkString(",").split(",")
                  .map((x: String) => (x, 1)).groupBy((t: Tuple2[String, Int]) => t._1)
                  .mapValues((arr: Array[Tuple2[String, Int]]) => arr.length)
                sender ! FileResultMsg(map)
              }
            }
          }
        }
      }
      
      object Scala_26_wordcount {
        def main(args: Array[String]): Unit = {
          val arr = Array("d:/a.txt", "d:/b.txt", "d:/c.txt")
          val list = ListBuffer[Future[Any]]()
          //陣列封裝了每個檔案處理好的資料
          val fileDataArray = ArrayBuffer[Map[String, Int]]()
      
          for (path <- arr) {
            val actor = new FileActor
            actor.start()
            //傳送非同步訊息 並且接受到每個檔案的處理結果
            val result = actor !! FilePathMsg(path)
            list += result
          }
      
          while (list.size > 0) {
            for (f <- list if f.isSet) {
              val fileResult = f.apply().asInstanceOf[FileResultMsg]
              fileDataArray += fileResult.result
              list -= f
            }
          }
          val wordcount = fileDataArray.flatten.groupBy((t: Tuple2[String, Int]) => t._1)
            .mapValues((arr: ArrayBuffer[Tuple2[String, Int]]) => {
              arr.map((t: Tuple2[String, Int]) => t._2).sum
            })
          println(wordcount)
        }
      }
      

相關文章