Scala泛型
泛型的定义
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)
}
}