2021年大数据常用语言Scala(三十六):scala高级用法 泛型
目錄
泛型
定義一個泛型方法
定義一個泛型類
上下界
協變、逆變、非變?
非變
協變
逆變
泛型
scala和Java一樣,類和特質、方法都可以支持泛型。我們在學習集合的時候,一般都會涉及到泛型。
scala>?val?list1:List[String]?=?List("1",?"2",?"3")
list1:?List[String]?=?List(1,?2,?3)scala>?val?list1:List[String]?=?List("1",?"2",?"3")
list1:?List[String]?=?List(1,?2,?3)
在scala中,使用方括號來定義類型參數。
定義一個泛型方法
需求:用一個方法來獲取任意類型數組的中間的元素
不考慮泛型直接實現(基于Array[Int]實現)
加入泛型支持
不考慮泛型的實現??
def?getMiddle(arr:Array[Int])?=?arr(arr.length /?2)def?main(args:?Array[String]):?Unit?=?{val?arr1 =?Array(1,2,3,4,5)println(getMiddle(arr1))}
?
加入泛型支持
??def?getMiddle[A](arr:Array[A])?=?arr(arr.length /?2)def?main(args:?Array[String]):?Unit?=?{val?arr1 =?Array(1,2,3,4,5)val?arr2 =?Array("a",?"b",?"c",?"d",?"f")println(getMiddle[Int](arr1))println(getMiddle[String](arr2))// 簡寫方式println(getMiddle(arr1))println(getMiddle(arr2))}
?
定義一個泛型類
我們接下來要實現一個Pair類(一對數據)來講解scala泛型相關的知識點。
Pair類包含兩個值,而且兩個值的類型不固定。
// 類名后面的方括號,就表示這個類可以使用兩個類型、分別是T和S
// 這個名字可以任意取
class?Pair[T,?S](val?first:?T,?val?second:?S)?case?class?Person(var?name:String,?val?age:Int)object?Pair?{def?main(args:?Array[String]):?Unit?=?{val?p1 =?new?Pair[String,?Int]("張三",?10)val?p2 =?new?Pair[String,?String]("張三",?"1988-02-19")val?p3 =?new?Pair[Person,?Person](Person("張三",?20),?Person("李四",?30))}
}
要定義一個泛型類,直接在類名后面加上方括號,指定要使用的類型參數。上述的T、S都是類型參數,就代表一個類型
指定了類對應的類型參數后,就可以使用這些類型參數來定義變量了
?
上下界
現在,有一個需求,在Pair類中,我們只想用來保存Person類型的對象,因為我們要添加一個方法,讓好友之間能夠聊天。例如:
def?chat(msg:String)?=?println(s"${first.name}對${second.name}說: $msg")
但因為,Pair類中根本不知道first有name這個字段,上述代碼會報編譯錯誤。
而且,添加了這個方法,就表示Pair類,現在只能支持Person類或者Person的子類的泛型。所以,我們需要給Pair的泛型參數,添加一個上界。
使用<: 類型名表示給類型添加一個上界,表示泛型參數必須要從上界繼承。
// 類名后面的方括號,就表示這個類可以使用兩個類型、分別是T和S
// 這個名字可以任意取
class?Pair[T <:?Person,?S <:Person](val?first:?T,?val?second:?S)?{def?chat(msg:String)?=?println(s"${first.name}對${second.name}說: $msg")
}class?Person(var?name:String,?val?age:Int)object?Pair?{def?main(args:?Array[String]):?Unit?=?{val?p3 =?new?Pair(new?Person("張三",?20),?new?Person("李四",?30))p3.chat("你好啊!")}
}
?
接著再提一個需求,Person類有幾個子類,分別是Policeman、Superman。
?
要控制Person只能和Person、Policeman聊天,但是不能和Superman聊天。此時,還需要給泛型添加一個下界。
// 類名后面的方括號,就表示這個類可以使用兩個類型、分別是T和S
// 這個名字可以任意取
class?Pair[T <:?Person,?S >:?Policeman <:Person](val?first:?T,?val?second:?S)?{def?chat(msg:String)?=?println(s"${first.name}對${second.name}說: $msg")
}class?Person(var?name:String,?val?age:Int)
class?Policeman(name:String,?age:Int)?extends?Person(name,?age)
class?Superman(name:String)?extends?Policeman(name,?-1)object?Pair?{def?main(args:?Array[String]):?Unit?=?{
// 編譯錯誤:第二個參數必須是Person的子類(包括本身)、Policeman的父類(包括本身)val?p3 =?new?Pair(new?Person("張三",?20),?new?Superman("李四"))p3.chat("你好啊!")}
}
U >: T 表示U必須是類型T的父類或本身
S <: T 表示S必須是類型T的子類或本身
?
協變、逆變、非變?
?
父類對象 可以指向 子類的實例,這是多態
如果是泛型之間呢?
來一個類型轉換的問題:
class?Pair[T]object?Pair?{def?main(args:?Array[String]):?Unit?=?{val?p1 =?Pair("hello")// 編譯報錯,無法將p1轉換為p2val?p2:Pair[AnyRef]?=?p1println(p2)}
}
?
非變
class Pair[T]{},這種情況就是非變(默認),類型B是A的子類型,Pair[A]和Pair[B]沒有任何從屬關系,這種情況和Java是一樣的。
?
協變
class Pair[+T],這種情況是協變。類型B是A的子類型,Pair[B]可以認為是Pair[A]的子類型。這種情況,參數化類型的方向和類型的方向是一致的。
?
逆變
class Pair[-T],這種情況是逆變。類型B是A的子類型,Pair[A]反過來可以認為是Pair[B]的子類型。這種情況,參數化類型的方向和類型的方向是相反的。
?
示例:
class?Super
class?Sub extends?Super//非變
class?Temp1[A](title:?String)
//協變
class?Temp2[+A](title:?String)
//逆變
class?Temp3[-A](title:?String)object?Covariance_demo {def?main(args:?Array[String]):?Unit?=?{val?a =?new?Sub()// 沒有問題,Sub是Super的子類val?b:Super =?a// 非變val?t1:Temp1[Sub]?=?new?Temp1[Sub]("測試")// 報錯!默認不允許轉換// val t2:Temp1[Super] = t1// 協變val?t3:Temp2[Sub]?=?new?Temp2[Sub]("測試")val?t4:Temp2[Super]?=?t3// 非變val?t5:Temp3[Super]?=?new?Temp3[Super]("測試")val?t6:Temp3[Sub]?=?t5}
}
?
總結
以上是生活随笔為你收集整理的2021年大数据常用语言Scala(三十六):scala高级用法 泛型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021年大数据常用语言Scala(三十
- 下一篇: 2021年大数据常用语言Scala(三十