二維碼
微世推網(wǎng)

掃一掃關(guān)注

當(dāng)前位置: 首頁(yè) » 快報(bào)資訊 » 今日快報(bào) » 正文

scala_泛型方法_類(lèi)_特質(zhì)的使用_泛型邊界_協(xié)變

放大字體  縮小字體 發(fā)布日期:2023-03-22 01:22:52    作者:葉辰銘    瀏覽次數(shù):225
導(dǎo)讀

1. 泛型泛型得意思是泛指某種具體得數(shù)據(jù)類(lèi)型, 在Scala中, 泛型用[數(shù)據(jù)類(lèi)型]表示. 在實(shí)際開(kāi)發(fā)中, 泛型一般是結(jié)合數(shù)組或者集合來(lái)使用得, 除此之外, 泛型得常見(jiàn)用法還有以下三種:泛型方法泛型類(lèi)泛型特質(zhì)1.1 泛型方法泛型方法指得是把泛型定義到方法聲明上, 即:該方法得參數(shù)類(lèi)型是由泛型來(lái)決定得. 在調(diào)用方法時(shí), 明確具體得數(shù)據(jù)

1. 泛型

泛型得意思是泛指某種具體得數(shù)據(jù)類(lèi)型, 在Scala中, 泛型用[數(shù)據(jù)類(lèi)型]表示. 在實(shí)際開(kāi)發(fā)中, 泛型一般是結(jié)合數(shù)組或者集合來(lái)使用得, 除此之外, 泛型得常見(jiàn)用法還有以下三種:

  • 泛型方法
  • 泛型類(lèi)
  • 泛型特質(zhì)1.1 泛型方法

    泛型方法指得是把泛型定義到方法聲明上, 即:該方法得參數(shù)類(lèi)型是由泛型來(lái)決定得. 在調(diào)用方法時(shí), 明確具體得數(shù)據(jù)類(lèi)型.

    格式

    def 方法名[泛型名稱(chēng)](..) = { //...}

    需求

    定義方法getMiddleElement(), 用來(lái)獲取任意類(lèi)型數(shù)組得中間元素.

  • 思路一: 不考慮泛型直接實(shí)現(xiàn)(基于Array[Int]實(shí)現(xiàn))
  • 思路二: 加入泛型支持.

    參考代碼

    //案例: 泛型方法演示.//細(xì)節(jié): 泛型方法在調(diào)用方法得時(shí)候 明確具體得數(shù)據(jù)類(lèi)型.object ClassDemo01 { //需求: 用一個(gè)方法來(lái)獲取任意類(lèi)型數(shù)組得中間得元素 //思路一:不考慮泛型直接實(shí)現(xiàn)(基于Array[Int]實(shí)現(xiàn)) //def getMiddleElement(arr: Array[Int]) = arr(arr.length / 2) //思路二: 加入泛型支持 def getMiddleElement[T](arr: Array[T]) = arr(arr.length / 2) def main(args: Array[String]): Unit = { //調(diào)用方法 println(getMiddleElement(Array(1, 2, 3, 4, 5))) println(getMiddleElement(Array("a", "b", "c"))) }}1.2 泛型類(lèi)

    泛型類(lèi)指得是把泛型定義到類(lèi)得聲明上, 即:該類(lèi)中得成員得參數(shù)類(lèi)型是由泛型來(lái)決定得. 在創(chuàng)建對(duì)象時(shí), 明確具體得數(shù)據(jù)類(lèi)型.

    格式

    class 類(lèi)[T](val 變量名: T)

    需求

    1. 定義一個(gè)Pair泛型類(lèi), 該類(lèi)包含兩個(gè)字段,且兩個(gè)字段得類(lèi)型不固定.
    2. 創(chuàng)建不同類(lèi)型得Pair泛型類(lèi)對(duì)象,并打印.

    參考代碼

    //案例: 泛型-演示泛型類(lèi)得使用.//泛型類(lèi): 在創(chuàng)建對(duì)象得時(shí)候, 明確具體得數(shù)據(jù)類(lèi)型.object ClassDemo02 { //1. 實(shí)現(xiàn)一個(gè)Pair泛型類(lèi) //2. Pair類(lèi)包含兩個(gè)字段,而且兩個(gè)字段得類(lèi)型不固定 class Pair[T](var a:T, var b:T) def main(args: Array[String]): Unit = { //3. 創(chuàng)建不同類(lèi)型泛型類(lèi)對(duì)象,并打印 var p1 = new Pair[Int](10, 20) println(p1.a, p1.b) var p2 = new Pair[String]("abc", "bcd") println(p2.a, p2.b) }}1.3 泛型特質(zhì)

    泛型特質(zhì)指得是把泛型定義到特質(zhì)得聲明上, 即:該特質(zhì)中得成員得參數(shù)類(lèi)型是由泛型來(lái)決定得. 在定義泛型特質(zhì)得子類(lèi)或者子單例對(duì)象時(shí), 明確具體得數(shù)據(jù)類(lèi)型.

    格式

    trait 特質(zhì)A[T] { //特質(zhì)中得成員}class 類(lèi)B extends 特質(zhì)A[指定具體得數(shù)據(jù)類(lèi)型] { //類(lèi)中得成員}

    需求

    1. 定義泛型特質(zhì)Logger, 該類(lèi)有一個(gè)變量a和show()方法, 它們都是用Logger特質(zhì)得泛型.
    2. 定義單例對(duì)象ConsoleLogger, 繼承Logger特質(zhì).
    3. 打印單例對(duì)象ConsoleLogger中得成員.

    參考代碼

    //案例: 演示泛型特質(zhì).object ClassDemo03 { //1. 定義泛型特質(zhì)Logger, 該類(lèi)有一個(gè)a變量和show()方法, 都是用Logger特質(zhì)得泛型. trait Logger[T] { //定義變量 val a:T //定義方法. def show(b:T) = println(b) } //2. 定義單例對(duì)象ConsoleLogger, 繼承Logger特質(zhì). object ConsoleLogger extends Logger[String]{ override val a: String = "張三" } //main方法, 作為程序得主入口. def main(args: Array[String]): Unit = { //3. 打印單例對(duì)象ConsoleLogger中得成員. println(ConsoleLogger.a) ConsoleLogger.show("10") }}2. 上下界

    我們?cè)谑褂梅盒?方法, 類(lèi), 特質(zhì))時(shí),如果要限定該泛型必須從哪個(gè)類(lèi)繼承、或者必須是哪個(gè)類(lèi)得父類(lèi)。此時(shí),就需要使用到泛型得上下界。

    2.1 上界

    使用T <: 類(lèi)型名表示給類(lèi)型添加一個(gè)上界,表示泛型參數(shù)必須要從該類(lèi)(或本身)繼承.

    格式

    [T <: 類(lèi)型]

    例如: [T <: Person]得意思是, 泛型T得數(shù)據(jù)類(lèi)型必須是Person類(lèi)型或者Person得子類(lèi)型

    需求

    1. 定義一個(gè)Person類(lèi)
    2. 定義一個(gè)Student類(lèi),繼承Person類(lèi)
    3. 定義一個(gè)泛型方法demo(),該方法接收一個(gè)Array參數(shù).
    4. 限定demo方法得Array元素類(lèi)型只能是Person或者Person得子類(lèi)
    5. 測(cè)試調(diào)用demo()方法,傳入不同元素類(lèi)型得Array

    參考代碼

    //案例: 演示泛型得上下界之 上界.object ClassDemo04 { //1. 定義一個(gè)Person類(lèi) class Person //2. 定義一個(gè)Student類(lèi),繼承Person類(lèi) class Student extends Person //3. 定義一個(gè)demo泛型方法,該方法接收一個(gè)Array參數(shù), //限定demo方法得Array元素類(lèi)型只能是Person或者Person得子類(lèi) def demo[T <: Person](arr: Array[T]) = println(arr) def main(args: Array[String]): Unit = { //4. 測(cè)試調(diào)用demo,傳入不同元素類(lèi)型得Array //demo(Array(1, 2, 3)) //這個(gè)會(huì)報(bào)錯(cuò), 因?yàn)橹荒軅魅隤erson或者它得子類(lèi)型. demo(Array(new Person())) demo(Array(new Student())) }}2.2 下界

    使用T >: 數(shù)據(jù)類(lèi)型表示給類(lèi)型添加一個(gè)下界,表示泛型參數(shù)必須是從該類(lèi)型本身或該類(lèi)型得父類(lèi)型.

    格式

    [T >: 類(lèi)型]

    注意:

    例如: [T >: Person]得意思是, 泛型T得數(shù)據(jù)類(lèi)型必須是Person類(lèi)型或者Person得父類(lèi)型

    如果泛型既有上界、又有下界。下界寫(xiě)在前面,上界寫(xiě)在后面. 即: [T >: 類(lèi)型1 <: 類(lèi)型2]

    需求

    1. 定義一個(gè)Person類(lèi)
    2. 定義一個(gè)Policeman類(lèi),繼承Person類(lèi)
    3. 定義一個(gè)Superman類(lèi),繼承Policeman類(lèi)
    4. 定義一個(gè)demo泛型方法,該方法接收一個(gè)Array參數(shù),
    5. 限定demo方法得Array元素類(lèi)型只能是Person、Policeman
    6. 測(cè)試調(diào)用demo,傳入不同元素類(lèi)型得Array

    參考代碼

    //案例: 演示泛型得上下界之 下界.//如果你在設(shè)定泛型得時(shí)候, 涉及到既有上界, 又有下界, 一定是: 下界在前, 上界在后.object ClassDemo05 { //1. 定義一個(gè)Person類(lèi) class Person //2. 定義一個(gè)Policeman類(lèi),繼承Person類(lèi) class Policeman extends Person //3. 定義一個(gè)Superman類(lèi),繼承Policeman類(lèi) class Superman extends Policeman //4. 定義一個(gè)demo泛型方法,該方法接收一個(gè)Array參數(shù), //限定demo方法得Array元素類(lèi)型只能是Person、Policeman // 下界 上界 def demo[T >: Policeman <: Policeman](arr: Array[T]) = println(arr) def main(args: Array[String]): Unit = { //5. 測(cè)試調(diào)用demo,傳入不同元素類(lèi)型得Array //demo(Array(new Person)) demo(Array(new Policeman)) //demo(Array(new Superman)) //會(huì)報(bào)錯(cuò), 因?yàn)橹荒軅魅? Policeman類(lèi)獲取它得父類(lèi)型, 而Superman是Policeman得子類(lèi)型, 所以不行. }}3. 協(xié)變、逆變、非變

    在Spark得源代碼中大量使用到了協(xié)變、逆變、非變,學(xué)習(xí)該知識(shí)點(diǎn)對(duì)我們將來(lái)閱讀spark源代碼很有幫助。

  • 非變: 類(lèi)A和類(lèi)B之間是父子類(lèi)關(guān)系, 但是Pair[A]和Pair[B]之間沒(méi)有任何關(guān)系.
  • 協(xié)變: 類(lèi)A和類(lèi)B之間是父子類(lèi)關(guān)系, Pair[A]和Pair[B]之間也有父子類(lèi)關(guān)系.
  • 逆變: 類(lèi)A和類(lèi)B之間是父子類(lèi)關(guān)系, 但是Pair[A]和Pair[B]之間是子父類(lèi)關(guān)系.

    如下圖:

    3.1 非變

    語(yǔ)法格式

    class Pair[T]{}

  • 默認(rèn)泛型類(lèi)是非變得
  • 即: 類(lèi)型B是A得子類(lèi)型,Pair[A]和Pair[B]沒(méi)有任何從屬關(guān)系3.2 協(xié)變

    語(yǔ)法格式

    class Pair[+T]

  • 類(lèi)型B是A得子類(lèi)型,Pair[B]可以認(rèn)為是Pair[A]得子類(lèi)型
  • 參數(shù)化類(lèi)型得方向和類(lèi)型得方向是一致得。3.3 逆變

    語(yǔ)法格式

    class Pair[-T]

  • 類(lèi)型B是A得子類(lèi)型,Pair[A]反過(guò)來(lái)可以認(rèn)為是Pair[B]得子類(lèi)型
  • 參數(shù)化類(lèi)型得方向和類(lèi)型得方向是相反得3.4 示例

    需求

    1. 定義一個(gè)Super類(lèi)、以及一個(gè)Sub類(lèi)繼承自Super類(lèi)
    2. 使用協(xié)變、逆變、非變分別定義三個(gè)泛型類(lèi)
    3. 分別創(chuàng)建泛型類(lèi)對(duì)象來(lái)演示協(xié)變、逆變、非變

    參考代碼

    //案例: 演示非變, 協(xié)變, 逆變.object ClassDemo06 { //1. 定義一個(gè)Super類(lèi)、以及一個(gè)Sub類(lèi)繼承自Super類(lèi) class Super //父類(lèi) class Sub extends Super //子類(lèi) //2. 使用協(xié)變、逆變、非變分別定義三個(gè)泛型類(lèi) class Temp1[T] //非變 class Temp2[+T] //協(xié)變 class Temp3[-T] //逆變. def main(args: Array[String]): Unit = { //3. 分別創(chuàng)建泛型類(lèi)來(lái)演示協(xié)變、逆變、非變 //演示非變. val t1:Temp1[Sub] = new Temp1[Sub] //val t2:Temp1[Super] = t1 //編譯報(bào)錯(cuò), 因?yàn)榉亲兪? Super和Sub有父子類(lèi)關(guān)系, 但是Temp1[Super] 和 Temp1[Sub]之間沒(méi)有關(guān)系. //演示協(xié)變 val t3:Temp2[Sub] = new Temp2[Sub] val t4:Temp2[Super] = t3 //不報(bào)錯(cuò), 因?yàn)閰f(xié)變是: Super和Sub有父子類(lèi)關(guān)系, 所以Temp2[Super] 和 Temp2[Sub]之間也有父子關(guān)系. //Temp2[Super]是父類(lèi)型, Temp2[Sub]是子類(lèi)型. //演示逆變 val t5:Temp3[Super] = new Temp3[Super] val t6:Temp3[Sub] = t5 //不報(bào)錯(cuò), 因?yàn)槟孀兪? Super和Sub有父子類(lèi)關(guān)系, 所以Temp3[Super] 和 Temp3[Sub]之間也有子父關(guān)系. //Temp3[Super]是子類(lèi)型, Temp3[Sub]是父類(lèi)型. }}4. 案例: 列表去重排序4.1 需求

    1. 已知當(dāng)前項(xiàng)目下得data文件夾中有一個(gè)1.txt文感謝件, 文件內(nèi)容如下:

    11653229311512

    1. 對(duì)上述數(shù)據(jù)去重排序后, 重新寫(xiě)入到data文件夾下得2.txt文感謝件中, 即內(nèi)容如下:

    12356911224.2 目得

    考察泛型, 列表, 流相關(guān)得內(nèi)容.

    4.3 參考代碼

    import java.io.{BufferedWriter, FileWriter}import scala.io.Source//案例: 列表去重排序, 并寫(xiě)入文件.object ClassDemo07 { def main(args: Array[String]): Unit = { //1. 定義數(shù)據(jù)源對(duì)象. val source = Source.fromFile("./data/1.txt") //2. 從指定文件中讀取所有得數(shù)據(jù)(字符串形式) val list1:List[String] = source.mkString.split("\\s+").toList //3. 把List[String]列表轉(zhuǎn)換成List[Int] val list2:List[Int] = list1.map(_.toInt) //4. 把List[Int]轉(zhuǎn)換成Set[Int], 對(duì)列表元素去重. val set:Set[Int] = list2.toSet //5. 把Set[Int]轉(zhuǎn)成List[Int], 然后升序排列 val list3:List[Int] = set.toList.sorted //println(list3) //6. 把數(shù)據(jù)重新寫(xiě)入到data文件夾下得2.txt文件中. val bw = new BufferedWriter(new FileWriter("./data/2.txt")) for(i <- list3) { bw.write(i.toString) bw.newline() //別忘記加換行 } //7. 釋放資源 bw.close() }}

  •  
    (文/葉辰銘)
    免責(zé)聲明
    本文僅代表發(fā)布者:葉辰銘個(gè)人觀點(diǎn),本站未對(duì)其內(nèi)容進(jìn)行核實(shí),請(qǐng)讀者僅做參考,如若文中涉及有違公德、觸犯法律的內(nèi)容,一經(jīng)發(fā)現(xiàn),立即刪除,需自行承擔(dān)相應(yīng)責(zé)任。涉及到版權(quán)或其他問(wèn)題,請(qǐng)及時(shí)聯(lián)系我們刪除處理郵件:weilaitui@qq.com。
     

    Copyright?2015-2025 粵公網(wǎng)安備 44030702000869號(hào)

    粵ICP備16078936號(hào)

    微信

    關(guān)注
    微信

    微信二維碼

    WAP二維碼

    客服

    聯(lián)系
    客服

    聯(lián)系客服:

    24在線QQ: 770665880

    客服電話: 020-82301567

    E_mail郵箱: weilaitui@qq.com

    微信公眾號(hào): weishitui

    韓瑞 小英 張澤

    工作時(shí)間:

    周一至周五: 08:00 - 24:00

    反饋

    用戶
    反饋