# 泛型的定義 ```Scala object _11_泛型 { def main(args: Array[String]): Unit = { //[A] 這個代表的就是泛型 ==》 在創建對象的時候,可以指定需要傳進去的類型 //作用就是在創建對象的時候,可以對傳進去的參數一個約束,當設置泛型位 ...
泛型的定義
object _11_泛型 {
def main(args: Array[String]): Unit = {
//[A] 這個代表的就是泛型 ==》 在創建對象的時候,可以指定需要傳進去的類型
//作用就是在創建對象的時候,可以對傳進去的參數一個約束,當設置泛型位int之後,那麼傳進去的值就必須是int
//apply[A](xs: A*): List[A] = xs.toList
val ints: List[Int] = List[Int](1, 2, 3, 4)
//自己寫一個? 單純演示泛型語法的定義,沒有什麼實際的意義
/**
* 將泛型定義在類上,那麼在整個類中,都可以使用該泛型,作用域是整個類
* @tparam T
*/
class TestFanXin[T](){
def max(a:T,b:T)= a
}
//如果設置泛型位Int類型,那麼方法的參數就只能傳Int類型
new TestFanXin[Int]().max(1,2)
//如果設置泛型位String類型,那麼方法的參數就只能傳String類型
new TestFanXin[String]().max("aa","bb")
/**
* 泛型也可以定義在方法上,如果定義在方法上,那麼該泛型的作用域只能作用在該方法中
* 出了該方法便不能生效
*/
class TestFanXin1(){
def max[T](a:T,b:T)= a
def min[A](a:A,b:A)= b
}
}
}
泛型上下限
泛型的上下限的作用是對傳入的泛型進行限定。
語法:
//泛型上限 只能夠傳Person 這個類和他的的子類
Class PersonList[T <: Person]{
}
//泛型下限 只能夠傳Person 這個類和他的的父類
Class PersonList[T >: Person]{
}
代碼示例:
package com.doit.day02
object _12_泛型的上下限 {
def main(args: Array[String]): Unit = {
def sayHi[A <: Father](a:A): Unit ={
println("test")
}
def sayHello[A >: Father](a:A): Unit ={
println("test")
}
//調用sayHi的時候,傳進去的參數因為有泛型的上界約定,所以只能傳入Father和Father的子類
sayHi(new Son())
sayHi(new Father())
//這邊編譯的時候雖然不報錯,但是運行的時候會報錯
// sayHi(new GrandFather())
//如果泛型是定義在方法上的,如果沒有加泛型,是限制不住的,但是加了泛型,還是可以限制住的
// sayHello[ABC](new ABC)
// sayHello[Son](new Son)
sayHello(new Father)
sayHello(new GrandFather)
class Test[A >:Father]{
def sayHi(a:A) ={
println("hello")
}
}
new Test[Father].sayHi(new Father)
//如果定義在類上的話,就能約束住了
// new Test[Son].sayHi(new Son)
new Test[GrandFather].sayHi(new GrandFather)
}
}
class Son extends Father
class Father extends GrandFather
class GrandFather
class ABC
視圖限定
約束本質:存在一個隱式轉換,能夠將T類型轉換成B類型
泛型視圖限定:T <% B
package com.doit.day02
object _13_視圖限定 {
def main(args: Array[String]): Unit = {
class Bird(val name:String){
def fly()={println(name + "飛走了")}
}
class ToyBird
def bitBird[T <% Bird](b:T)=b.fly()
bitBird[Bird](new Bird("小鳥"))
implicit def toy2Bird(toyBird: ToyBird)= new Bird("玩具鳥")
bitBird[ToyBird](new ToyBird)
}
}
上下文限定
上下文限定是將泛型和隱式轉換的結合產物,以下兩者功能相同,使用上下文限定[A : Ordering]之後,方法內無法使用隱式參數名調用隱式參數,需要通過 implicitly[Ordering[A]]獲取隱式變數,如果此時無法查找到對應類型的隱式變數,會發生出錯誤。
implicit val x = 1
val y = implicitly[Int]
val z = implicitly[Double]
語法:
def f[A : B](a: A) = println(a)
//等同於 def f[A](a:A)(implicit arg:B[A])=println(a)```
代碼示例:
```Scala
package com.doit.day02
object _14_上下文界定 {
def main(args: Array[String]): Unit = {
/**
* 泛型的上下文界定
*/
case class Tiger(age:Int,weight:Int)
case class Cat(age:Int,weight:Int)
//我想比較兩個老虎的大小 單純的老虎,沒有實現compare方法的話,是沒有辦法調用compare來比較的
//兩個辦法,第一個辦法,在類上實現Ordered 特質,重寫 compareTo方法
//第二個方法,傳一個比較器進去,這樣他們就可以用比較器來比較了
def bigger(tiger: Tiger,tiger1:Tiger,cmp:Ordering[Tiger]):Tiger={
if (cmp.compare(tiger,tiger1)> 0) tiger else tiger1
}
//上面這種方法確實是可以比較,但是只能比較老虎,我想比較個貓好像就比較不了了
//想比較貓,得重新在寫一個
def bigger1(cat: Cat,cat1:Cat,cmp:Ordering[Cat]):Cat={
if (cmp.compare(cat,cat1)> 0) cat else cat1
}
//不過回頭想比較狗狗,又要寫一個,比較麻煩,不通用
//這時候就可以定義泛型了
def bigger2[T](t: T,t1:T,cmp:Ordering[T]):T={
if (cmp.compare(t,t1)> 0) t else t1
}
//方法的調用 這樣是沒什麼問題的
//但是在馬大爺眼裡,這麼寫代碼,多low啊,不符合馬大爺的氣質,他就開始搞事情了
bigger2[Cat](Cat(10,100),Cat(20,80),new Ordering[Cat] {
override def compare(x: Cat, y: Cat) = x.age - y.age
})
//咱們不是有隱式轉換嘛,能不能把這個比較器呢?
//我上下文中找找,有沒有什麼隱式的比較器可以拿過來用,如果有我就直接拿過來,這樣就不用傳比較器了,去偷一個不香嘛
//bigger3[T :Ordering] 註意:如果想讓他自己偷一個,那麼需要實現上下文界定,不然是沒辦法使用的
def bigger3[T :Ordering](t: T,t1:T):T={
if(implicitly[Ordering[T]].compare(t,t1)>0) t else t1
}
/**
* 兩種創建隱式比較器對象的寫法
*/
// implicit val value: Ordering[Cat] = new Ordering[Cat] {
// override def compare(x: Cat, y: Cat) = x.age - y.age
// }
implicit val value1 = Ordering.by[Cat,Int](cat=>cat.age)
bigger3[Cat](Cat(10,100),Cat(20,80))
}
}
逆變,協變,不變
語法:
不變:預設
協變: +T
逆變: -T
package com.doit.day02
/**
*
* 不變:預設
* 協變: +T
* 逆變: -T
*/
object _15_逆變協變不變 {
def main(args: Array[String]): Unit = {
class Box[T](t:T)
class Pencil
class YZPencil extends Pencil
/**
* 本身我的pencil 和YZpencil 是父子關係
* 那麼按照常理來說,我裝筆的盒子也是圓珠筆的盒子的父類,這樣的話咱們能夠理解
* 我盒子既然能裝筆,而且圓珠筆又是筆的父類,所以我這個盒子應該能裝圓珠筆
* 畢竟有多態的存在,我的筆本身可以接收圓珠筆的 ==>理解 ?
*/
val box1: Box[Pencil] = new Box[Pencil](new Pencil)
val box2: Box[YZPencil] = new Box[YZPencil](new YZPencil)
//但是在代碼中,卻不能這麼操作 雖然圓珠筆和筆存在父子關係,但是一旦把他們裝在盒子中,就不存在這樣的關係了
//這種的關係我們稱他為不變
// val box3: Box[Pencil] = new Box[YZPencil](new YZPencil) //報錯
//如果想讓他們依然有關係,可以的,scala給我提供了另外一種方式叫協變和逆變
class Box1[+T](t:T)
class Pencil1
class YZPencil1 extends Pencil1
//本身圓珠筆是筆的子類,加上了協變這麼一個操作 那麼裝筆的盒子就是裝圓珠筆的父類了
val box3: Box1[Pencil1] = new Box1[YZPencil1](new YZPencil1)
// 逆變
//如果想讓他們依然有關係,可以的,scala給我提供了另外一種方式叫協變和逆變
class Box2[-T](t:T)
class Pencil2
class YZPencil2 extends Pencil2
//本身圓珠筆是筆的子類,加上了逆變這麼一個操作 那麼裝筆的盒子就是裝圓珠筆的子類了(父子關係顛倒過來了)
val box4: Box2[YZPencil2] = new Box2[Pencil2](new Pencil2)
}
}