十四、泛型
泛型類
類似於Java,類和特質可以攜帶類型參數
class Student[T, S](var name: T, var age: S) { // T S K
// <> ---> [T,S,K]
}
object Student {
def main(args: Array[String]): Unit = {
// 創建類時,手動指定泛型類型
val stu = new Student[String, Int]("zs", 18)
println(stu.name + "\t" + stu.age)
// 採用自動推斷
val stu2= new Student("zs", 18)
println(stu2.name + "\t" + stu2.age)
}
}
泛型方法和函數
函數和方法也可以帶類型參數
def format[T](x: Array[T]) = { //類型參數放在方法名之後
println(x.mkString(","))
}
def format2[T](x: Array[T]): Array[String] = {
x.map(_ + "")
}
// 調用時,手動指定泛型類型
format[Int](Array(1, 2, 3, 4))
// 或
format(Array(1, 2, 3, 4))
println(format2(Array[Int](1,2,3,4)).mkString("|"))
返回值泛型需要根據傳入參數動態改變
上邊界
語法:[T <: S]
, 限定T類型必須是S的子類型 ,包含S類型本身
trait Animals
class Dog extends Animals
class Keeper[U <: Animals] { // 表示Keeper的實現類只能飼養Animal以及Animal的子類
def keep(a: U): Unit = {
println("飼養動物:"+a.getClass)
}
}
object Keeper {
def main(args: Array[String]): Unit = {
val dog = new Dog
new Keeper[Dog]().keep(dog)
}
}
下邊界
語法:[T >: s]
,限定T類型必須S的父類型
class Animals
class Dog extends Animals
class Car
class Keeper2[T >: Dog] { // 表示Keeper的實現類只能飼養Dog或者Dog的父類
def keeper(d: T) {
println("飼養狗的同類..." + d.getClass)
}
}
object Keeper2 {
def main(args: Array[String]): Unit = {
new Keeper2[Dog].keeper(new Dog)
new Keeper2[Animals].keeper(new Animals)
new Keeper2[Car] //error
}
}
下邊界範圍:包含父類 間接父類和本身
視圖限定
語法:[T <% S]
, 運行時嘗試將T類型隱式轉換爲S類型
package generic.viewlimit
import java.text.SimpleDateFormat
import java.util.Date
/**
* 視圖限定 嘗試通過隱式轉換將T 類型轉換Date類型
*
* @param first 傳進來的是字符串
*
*/
class Convert[T <% Date](val first: T) {
def print() = {
println(first.toLocaleString)
}
}
object Convert {
// 定義隱式轉換函數
implicit def str2Date(str:String):Date = {
new SimpleDateFormat("yyyy-MM-dd").parse(str)
}
def main(args: Array[String]): Unit = {
val c1 = new Convert[String]("2018-10-10")
c1.print()
}
}
上下文限定
上下文界定的形式爲T:M,其中M是另一個泛型類,它要求必須存在一個類型爲M[T]的隱式值。
package generic
/**
* 1) 要求:使用上下文界定+隱式值的方式,比較兩個Person對象的年齡大小
* 2) 要求:使用Ordering實現比較
*/
class Person(var name: String, var age: Int)
object Person {
//1. 聲明一個隱式值
implicit val ordering: Ordering[Person] = new Ordering[Person]() {
/**
* 比較大小的方法
*
* @param x
* @param y
* @return 1 大於 -1 小於
*/
override def compare(x: Person, y: Person): Int = {
if (x.age > y.age) 1
else -1
}
}
def main(args: Array[String]): Unit = {
val p1 = new Person("zs", 10)
val p2 = new Person("ls", 100)
val tools = new CompareUtils[Person](p1, p2)
if (tools.comparable() == 1) {
println("大於")
} else {
println("小於")
}
}
}
// 上下文限定 T:M M必須是一個泛型類 M[S]泛型類必須得有個隱式值
class CompareUtils[T: Ordering](p1: T, p2: T) {
def comparable() = {
// 獲取隱式值
val tools = implicitly[Ordering[T]]
tools.compare(p1, p2)
}
}
多重限定
A和B爲T上界
class A
class B extends A
class C extends B
/*
trait A
trait B
class C extends B with A // 動態混入
*/
// 多重 上邊界 T類型必須同時是A和B類型的子類型【並且】
class E[T <: A with B](t:T)
object E{
def main(args: Array[String]): Unit = {
val e1 = new E[C](new C)
}
}
A和B爲T下界
class A
class B extends A
class C
class D extends C
class E[T >: B with D](t: T) // T 類性是B類性或C類型父類型
object E {
def main(args: Array[String]): Unit = {
val e1 = new E[A](new A) // ok
val e2 = new E[B](new B) // ok
val e3 = new E[C](new C) // ok
val e4 = new E[D](new D) //OK
}
}
同時擁有上界和下界,並且A爲下界,B爲上界,A爲B的子類,順序不能顛倒
class A
class B extends A
class C extends B
class D[T >: C <: A](t: T)
object D {
def main(args: Array[String]): Unit = {
val d = new D[B](new B)
}
}
視圖界定,即同時能夠滿足隱式轉換的A和隱式轉換的B (略)
def say[T <% A <% B](v:T):Unit={
println(v)
}
trait A{}
trait B{}
+A 協變 [+T]
C[T1]是 C[T]的子類
// dog[T1] 是 animals [T]子類
// Convariant[T1] ---> Convariant[T] 的子類
class Animals
class Dog extends Animals
class A[+T]
object Dog {
def main(args: Array[String]): Unit = {
// 協變
val a = new A[Dog]()
val a2: A[Animals] = a // 父子關係 A[Dog] extends A[Animals]
}
}
// java
// Dog ---> Animals
// List<Dog> ---> List<Animals>
-A 逆變 [-T]
C[T] 是 C[T1]的子類
class Covariant[-T](t:T){}
val cov = new Covariant[Animal](new Animal("動物"))
val cov2:Covariant[Dog] = cov
A 不變 [T]
C[T] 與 C[T1]不相關
class Animals2
class Dog2 extends Animals2
class A2[-T]
object Dog2 {
def main(args: Array[String]): Unit = {
// 逆變
val a = new A2[Animals2]()
val a2: A2[Dog2] = a // 父子關係 A[Animals] extends A[Dog]
}
}