天天看點

|NO.Z.00074|——————————|BigDataEnd|——|Hadoop&Scala.V01|——|Scala.v01|擴充|類型參數|

一、類型參數

### --- 擴充大綱

~~~     類型參數
~~~     泛型類、泛型函數、協變和逆變
~~~     Akka      
### --- 類型參數

~~~     Scala的類型參數與Java的泛型是一樣的,
~~~     可以在集合、類、函數中定義類型參數,進而保證程式更好的健壯性。      
### --- 泛型類

~~~     泛型類,顧名思義,其實就是在類的聲明中定義一些泛型類型,
~~~     然後在類内部的字段或者方法,就可以使用這些泛型類型。
~~~     使用泛型類,通常是需要對類中的某些成員,
~~~     比如某些字段和方法中的參數或變量進行統一的類型限制,這樣可以保證程式更好的健壯性和穩定性。
~~~     如果不使用泛型進行統一的類型限制,那麼在後期程式運作過程中難免會出現問題,
~~~     比如傳入了不希望的類型導緻程式出問題。
~~~     在使用泛型類的時候,比如建立泛型類的對象,隻需将類型參數替換為實際的類型即可。
~~~     Scala自動推斷泛型類型特性:直接給使用泛型類型的字段指派時,Scala會自動進行類型推斷。      
### --- 泛型類的定義如下:

~~~     # 定義一個泛型類
class Stack[T1, T2, T3](name: T1) {
    var age: T2 = _
    var address: T3 = _
    def getInfo: Unit = {
        println(s"$name,$age,$address")
    }
    }      
~~~     # 使用上述的泛型類,隻需要使用具體的類型代替類型參數即可。

object GenericityDemo {
    def main(args: Array[String]): Unit = {
        //建立泛型類對象
        val stack = new Stack[String, Int, String]("lisi")
    stack.age = 20
    stack.address = "北京"
    stack.getInfo
}
}      

二、泛型函數

### --- 泛型函數

~~~     泛型函數,與泛型類類似,可以給某個函數在聲明時指定泛型類型,然後在函數體内,
~~~     多個變量或者傳回值之間,就可以使用泛型類型進行聲明,
~~~     進而對某個特殊的變量,或者多個變量,進行強制性的類型限制。
~~~     與泛型類一樣,你可以通過給使用了泛型類型的變量傳遞值來讓Scala自動推斷泛型的實際類型,
~~~     也可以在調用函數時,手動指定泛型類型。      
### --- 案例:卡片售賣機,可以指定卡片的内容,内容可以是String類型或Int類型

object GenericityFunction {
    def getCard[T](content: T) = {
        content match {
        case content: Int => s"card:$content is Int "
        case content: String => s"card:$content is String"
        case _ => s"card:$content"
    }
}

def main(args: Array[String]): Unit = {
    println(getCard[String]("hello"))
    println(getCard(1001))
}
}      

三、程式設計實作

### --- 程式設計代碼

package yanqi.cn.part11

//定義一個泛型類
class Stack[T1, T2, T3](name: T1) {
  var age: T2 = _
  var address: T3 = _

  def getInfo: Unit = {
    println(s"$name,$age,$address")
  }
}


object GenericityDemo {
  def main(args: Array[String]): Unit = {
    //建立泛型類的對象
    val stack=new Stack[String,Int,String]("lisi")
    stack.age=20
    stack.address="北京"

    stack.getInfo
  }
}      
### --- 編譯列印

D:\JAVA\jdk1.8.0_231\bin\java.exe "-javaagent:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=61763:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVA\jdk1.8.0_231\jre\lib\charsets.jar;D:\JAVA\jdk1.8.0_231\jre\lib\deploy.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\dnsns.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jaccess.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\localedata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\nashorn.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunec.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\zipfs.jar;D:\JAVA\jdk1.8.0_231\jre\lib\javaws.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jce.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfr.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfxswt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jsse.jar;D:\JAVA\jdk1.8.0_231\jre\lib\management-agent.jar;D:\JAVA\jdk1.8.0_231\jre\lib\plugin.jar;D:\JAVA\jdk1.8.0_231\jre\lib\resources.jar;D:\JAVA\jdk1.8.0_231\jre\lib\rt.jar;E:\NO.Z.10000——javaproject\NO.Z.00002.Hadoop\ScalaPro\out\production\ScalaPro;D:\JAVA\scala-2.12.2\lib\scala-library.jar;D:\JAVA\scala-2.12.2\lib\scala-reflect.jar yanqi.cn.part11.GenericityDemo
lisi,20,北京

Process finished with exit code 0      

四、協變和逆變

### --- 協變和逆變

~~~     Scala的協變和逆變是非常有特色的,完全解決了Java中的泛型的一大缺憾!
~~~     舉例來說,Java中,如果有Professional是Master的子類,那麼Card[Professionnal]是不是Card[Master]的子類?答案是:不是。是以對于開發程式造成了很多的麻煩。
~~~     而Scala中,隻要靈活使用協變和逆變,就可以解決Java泛型的問題。
~~~     協變定義形式如:trait List[+T] {}
~~~     當類型S是類型A的子類型時,則List[S]也可以認為是List[A}的子類型,即List[S]可以泛化為List[A],
~~~     也就是被參數化,類型的泛化方向與參數類型的方向是一緻的,是以稱為協變(covariance)。
~~~     逆變定義形式如:trait List[-T] {}
~~~     當類型S是類型A的子類型,則Queue[A]反過來可以認為是Queue[S}的子類型,
~~~     也就是被參數化類型的泛化方向與參數類型的方向是相反的,是以稱為逆變(contravariance)。
~~~     # 小結:
~~~     如果A是B的子類,那麼在協變中,List[A]就是List[B]的子類; 在逆變中,List[A]就是List[B]的父類。      
### --- 協變案例:隻有大師以及大師級别以下的名片都可以進入會場

package yanqi.cn.part11
//大師
class Master
    //專家
    class Professor extends Master
    //講師
    class Teacher
        //這個是協變,Professor是Master的子類,此時Card[Profesor]也是Card[Master]的子類
        class Card[+T]
object CovarianceDemo {
    def enterMeet(card: Card[Master]): Unit = {
        //隻有Card[Master]及其子類Card[Professor]才能進入會場。
        println("歡迎進入會場!")
    }
    def main(args: Array[String]): Unit = {
        val masterCard = new Card[Master]
        val professorCard = new Card[Professor]
    val teacharCard = new Card[Teacher]
    enterMeet(masterCard)
    enterMeet(professorCard)
    //此處就會報錯
    //enterMeet(teacharCard)
}
}      
### --- 程式設計代碼

package yanqi.cn.part11

//大師
class Master

//專家
class Professor extends Master

//講師
class Teacher

//定義協變
//class Card[+T]

//定義逆變
class Card[-T]

object ConvarianceDemo {
  def enterMeet(card: Card[Professor]): Unit = {
    //隻有Card[Master]和它的子類才能進入會場
    println("歡迎進入會場!")
  }

  def main(args: Array[String]): Unit = {
    val masterCard = new Card[Master]
    val professorCard = new Card[Professor]
    val teacherCard = new Card[Teacher]

    enterMeet(masterCard)
    enterMeet(professorCard)
//    enterMeet(teacherCard)
  }
}      
### --- 編譯列印

D:\JAVA\jdk1.8.0_231\bin\java.exe "-javaagent:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=61585:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVA\jdk1.8.0_231\jre\lib\charsets.jar;D:\JAVA\jdk1.8.0_231\jre\lib\deploy.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\dnsns.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jaccess.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\localedata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\nashorn.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunec.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\zipfs.jar;D:\JAVA\jdk1.8.0_231\jre\lib\javaws.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jce.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfr.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfxswt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jsse.jar;D:\JAVA\jdk1.8.0_231\jre\lib\management-agent.jar;D:\JAVA\jdk1.8.0_231\jre\lib\plugin.jar;D:\JAVA\jdk1.8.0_231\jre\lib\resources.jar;D:\JAVA\jdk1.8.0_231\jre\lib\rt.jar;E:\NO.Z.10000——javaproject\NO.Z.00002.Hadoop\ScalaPro\out\production\ScalaPro;D:\JAVA\scala-2.12.2\lib\scala-library.jar;D:\JAVA\scala-2.12.2\lib\scala-reflect.jar yanqi.cn.part11.ConvarianceDemo
歡迎進入會場!
歡迎進入會場!

Process finished with exit code 0