十四、泛型
泛型类
类似于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]
}
}