Java Scala泛型(泛型方法,泛型類,泛型特質,上下界,協(xié)變、逆變、非變)
1. 泛型
泛型的意思是泛指某種具體的數(shù)據(jù)類型, 在Scala中, 泛型用[數(shù)據(jù)類型]表示. 在實際開發(fā)中, 泛型一般是結合數(shù)組或者集合來使用的, 除此之外, 泛型的常見用法還有以下三種:
- 泛型方法
- 泛型類
- 泛型特質
1.1 泛型方法
泛型方法指的是把泛型定義到方法聲明上, 即:該方法的參數(shù)類型是由泛型來決定的. 在調用方法時, 明確具體的數(shù)據(jù)類型.
格式
def 方法名[泛型名稱](..) = {
//...
}需求
定義方法getMiddleElement(), 用來獲取任意類型數(shù)組的中間元素.
- 思路一: 不考慮泛型直接實現(xiàn)(基于Array[Int]實現(xiàn))
- 思路二: 加入泛型支持.
參考代碼
//案例: 泛型方法演示.
//細節(jié): 泛型方法在調用方法的時候 明確具體的數(shù)據(jù)類型.
object ClassDemo01 {
//需求: 用一個方法來獲取任意類型數(shù)組的中間的元素
//思路一:不考慮泛型直接實現(xiàn)(基于Array[Int]實現(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 = {
//調用方法
println(getMiddleElement(Array(1, 2, 3, 4, 5)))
println(getMiddleElement(Array("a", "b", "c")))
}
}1.2 泛型類
泛型類指的是把泛型定義到類的聲明上, 即:該類中的成員的參數(shù)類型是由泛型來決定的. 在創(chuàng)建對象時, 明確具體的數(shù)據(jù)類型.
格式
class 類[T](val 變量名: T)
需求
- 定義一個Pair泛型類, 該類包含兩個字段,且兩個字段的類型不固定.
- 創(chuàng)建不同類型的Pair泛型類對象,并打印.
參考代碼
//案例: 泛型-演示泛型類的使用.
//泛型類: 在創(chuàng)建對象的時候, 明確具體的數(shù)據(jù)類型.
object ClassDemo02 {
//1. 實現(xiàn)一個Pair泛型類
//2. Pair類包含兩個字段,而且兩個字段的類型不固定
class Pair[T](var a:T, var b:T)
def main(args: Array[String]): Unit = {
//3. 創(chuàng)建不同類型泛型類對象,并打印
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 泛型特質
泛型特質指的是把泛型定義到特質的聲明上, 即:該特質中的成員的參數(shù)類型是由泛型來決定的. 在定義泛型特質的子類或者子單例對象時, 明確具體的數(shù)據(jù)類型.
格式
trait 特質A[T] {
//特質中的成員
}
class 類B extends 特質A[指定具體的數(shù)據(jù)類型] {
//類中的成員
}需求
- 定義泛型特質Logger, 該類有一個變量a和show()方法, 它們都是用Logger特質的泛型.
- 定義單例對象ConsoleLogger, 繼承Logger特質.
- 打印單例對象ConsoleLogger中的成員.
參考代碼
//案例: 演示泛型特質.
object ClassDemo03 {
//1. 定義泛型特質Logger, 該類有一個a變量和show()方法, 都是用Logger特質的泛型.
trait Logger[T] {
//定義變量
val a:T
//定義方法.
def show(b:T) = println(b)
}
//2. 定義單例對象ConsoleLogger, 繼承Logger特質.
object ConsoleLogger extends Logger[String]{
override val a: String = "張三"
}
//main方法, 作為程序的主入口.
def main(args: Array[String]): Unit = {
//3. 打印單例對象ConsoleLogger中的成員.
println(ConsoleLogger.a)
ConsoleLogger.show("10")
}
}2. 上下界
在使用泛型(方法, 類, 特質)時,如果要限定該泛型必須從哪個類繼承、或者必須是哪個類的父類。此時,就需要使用到泛型的上下界。
2.1 上界
使用T <: 類型名表示給類型添加一個上界,表示泛型參數(shù)必須要從該類(或本身)繼承.
格式
[T <: 類型]
例如: [T <: Person]的意思是, 泛型T的數(shù)據(jù)類型必須是Person類型或者Person的子類型
需求
- 定義一個Person類
- 定義一個Student類,繼承Person類
- 定義一個泛型方法demo(),該方法接收一個Array參數(shù).
- 限定demo方法的Array元素類型只能是Person或者Person的子類
- 測試調用demo()方法,傳入不同元素類型的Array
參考代碼
//案例: 演示泛型的上下界之 上界.
object ClassDemo04 {
//1. 定義一個Person類
class Person
//2. 定義一個Student類,繼承Person類
class Student extends Person
//3. 定義一個demo泛型方法,該方法接收一個Array參數(shù),
//限定demo方法的Array元素類型只能是Person或者Person的子類
def demo[T <: Person](arr: Array[T]) = println(arr)
def main(args: Array[String]): Unit = {
//4. 測試調用demo,傳入不同元素類型的Array
//demo(Array(1, 2, 3)) //這個會報錯, 因為只能傳入Person或者它的子類型.
demo(Array(new Person()))
demo(Array(new Student()))
}
}2.2 下界
使用T >: 數(shù)據(jù)類型表示給類型添加一個下界,表示泛型參數(shù)必須是從該類型本身或該類型的父類型.
格式
[T >: 類型]
注意:
例如: [T >: Person]的意思是, 泛型T的數(shù)據(jù)類型必須是Person類型或者Person的父類型如果泛型既有上界、又有下界。下界寫在前面,上界寫在后面. 即: [T >: 類型1 <: 類型2]
需求
- 定義一個Person類
- 定義一個Policeman類,繼承Person類
- 定義一個Superman類,繼承Policeman類
- 定義一個demo泛型方法,該方法接收一個Array參數(shù),
- 限定demo方法的Array元素類型只能是Person、Policeman
- 測試調用demo,傳入不同元素類型的Array
參考代碼
//案例: 演示泛型的上下界之 下界.
//如果你在設定泛型的時候, 涉及到既有上界, 又有下界, 一定是: 下界在前, 上界在后.
object ClassDemo05 {
//1. 定義一個Person類
class Person
//2. 定義一個Policeman類,繼承Person類
class Policeman extends Person
//3. 定義一個Superman類,繼承Policeman類
class Superman extends Policeman
//4. 定義一個demo泛型方法,該方法接收一個Array參數(shù),
//限定demo方法的Array元素類型只能是Person、Policeman
// 下界 上界
def demo[T >: Policeman <: Policeman](arr: Array[T]) = println(arr)
def main(args: Array[String]): Unit = {
//5. 測試調用demo,傳入不同元素類型的Array
//demo(Array(new Person))
demo(Array(new Policeman))
//demo(Array(new Superman)) //會報錯, 因為只能傳入: Policeman類獲取它的父類型, 而Superman是Policeman的子類型, 所以不行.
}
}3. 協(xié)變、逆變、非變
在Spark的源代碼中大量使用到了協(xié)變、逆變、非變,學習該知識點對閱讀spark源代碼很有幫助。
- 非變: 類A和類B之間是父子類關系, 但是Pair[A]和Pair[B]之間沒有
任何關系. - 協(xié)變: 類A和類B之間是父子類關系, Pair[A]和Pair[B]之間也有
父子類關系. - 逆變: 類A和類B之間是父子類關系, 但是Pair[A]和Pair[B]之間是
子父類關系.
如下圖:

3.1 非變
語法格式
class Pair[T]{}- 默認泛型類是
非變的 - 即: 類型B是A的子類型,Pair[A]和Pair[B]沒有任何從屬關系 3.2 協(xié)變
語法格式
class Pair[+T]
- 類型B是A的子類型,Pair[B]可以認為是Pair[A]的子類型
- 參數(shù)化類型的方向和類型的方向是一致的。
3.3 逆變
語法格式
class Pair[-T]
- 類型B是A的子類型,Pair[A]反過來可以認為是Pair[B]的子類型
- 參數(shù)化類型的方向和類型的方向是相反的
3.4 示例
需求
- 定義一個Super類、以及一個Sub類繼承自Super類
- 使用協(xié)變、逆變、非變分別定義三個泛型類
- 分別創(chuàng)建泛型類對象來演示協(xié)變、逆變、非變
參考代碼
//案例: 演示非變, 協(xié)變, 逆變.
object ClassDemo06 {
//1. 定義一個Super類、以及一個Sub類繼承自Super類
class Super //父類
class Sub extends Super //子類
//2. 使用協(xié)變、逆變、非變分別定義三個泛型類
class Temp1[T] //非變
class Temp2[+T] //協(xié)變
class Temp3[-T] //逆變.
def main(args: Array[String]): Unit = {
//3. 分別創(chuàng)建泛型類來演示協(xié)變、逆變、非變
//演示非變.
val t1:Temp1[Sub] = new Temp1[Sub]
//val t2:Temp1[Super] = t1 //編譯報錯, 因為非變是: Super和Sub有父子類關系, 但是Temp1[Super] 和 Temp1[Sub]之間沒有關系.
//演示協(xié)變
val t3:Temp2[Sub] = new Temp2[Sub]
val t4:Temp2[Super] = t3 //不報錯, 因為協(xié)變是: Super和Sub有父子類關系, 所以Temp2[Super] 和 Temp2[Sub]之間也有父子關系.
//Temp2[Super]是父類型, Temp2[Sub]是子類型.
//演示逆變
val t5:Temp3[Super] = new Temp3[Super]
val t6:Temp3[Sub] = t5 //不報錯, 因為逆變是: Super和Sub有父子類關系, 所以Temp3[Super] 和 Temp3[Sub]之間也有子父關系.
//Temp3[Super]是子類型, Temp3[Sub]是父類型.
}
}到此這篇關于Scala泛型(泛型方法,泛型類,泛型特質,上下界,協(xié)變、逆變、非變)的文章就介紹到這了,更多相關Scala泛型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
idea創(chuàng)建SpringBoot項目時Type選maven?project和maven?pom有何區(qū)別
Maven是一個Java工程的管理工具,跟其相同功能的工具如Gradle,下面這篇文章主要給大家介紹了關于idea創(chuàng)建SpringBoot項目時Type選maven?project和maven?pom有何區(qū)別的相關資料,需要的朋友可以參考下2023-02-02
Java MongoDB數(shù)據(jù)庫連接方法梳理
MongoDB作為一種介于關系型數(shù)據(jù)庫和非關系型數(shù)據(jù)庫之間的產(chǎn)品,它可以提供可擴展的高性能的數(shù)據(jù)存儲解決方案,近些年來受到了開發(fā)者的喜愛2022-08-08
高效數(shù)據(jù)傳輸?shù)拿孛芪淦鱌rotobuf的使用教程
Protobuf(Protocol?Buffers)是由?Google?開發(fā)的一種輕量級、高效的數(shù)據(jù)交換格式,它被用于結構化數(shù)據(jù)的序列化、反序列化和傳輸,本文主要介紹了它的具體使用方法,需要的可以參考一下2023-05-05
SpringBoot2整合Redis實現(xiàn)讀寫操作
Redis,對于大家來說應該不陌生,是經(jīng)常使用的開發(fā)技術之一。本文將結合實例代碼,介紹SpringBoot2整合Redis實現(xiàn)讀寫操作,感興趣的小伙伴們可以參考一下2021-07-07

