1.什么是泛型,作用
2.使用类型参数
[]内存放类型参数列表,下例中是一个泛型的stack,用户可以指定参数类型
class Stack[A] {
private var elements: List[A] = Nil
def push(x: A): Unit = elements = x :: elements
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}
3.指定参数类型
下例中用户指定了具体的参数类型为int
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // prints 2
println(stack.pop) // prints 1
4.泛型间的继承关系
和类型将的继承关系一模一样。
如果用户指定了具体的参数类型,其子类型也可以传入
例1
class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana
stack.push(apple)
stack.push(banana)
普通类间的继承关系
class Animal() {}
class Cat() extends Animal {}
val data = Seq[Animal](new Cat(),new Animal())
注意:和类间的继承关系一样,泛型类型的子类型是不可传导的。
这表示如果我们有一个字母类型的栈 Stack[Char],那它不能被用作一个整型的栈 Stack[Int]。否则就是不安全的,因为它将使我们能够在字母型的栈中插入真正的整型值。结论就是,只有当类型 B = A 时, Stack[A] 是 Stack[B] 的子类型才成立。因为此处可能会有很大的限制,Scala 提供了一种 类型参数注释机制 用以控制泛型类型的子类型的行为。
如下面两个例子
无论是直接的赋值,还是传参,都无法将new ListData[Cat]()
当做ListData[Animal]
使用。这里可以通过协变
实现。
5.型变
1.协变[+T]
即使用协变,允许将子类作为父类进行使用。上面的例子如果使用了协变就可以实现
- 赋值的例子
class Animal() {} class Cat() extends Animal {} class ListData[+T] {} val data2 = new ListData[Cat]() val data3: ListData[Animal] = data2
- 传参的例子
class Animal() {} class Cat() extends Animal {} class ListData[+T] {} def getAnimal(animal: ListData[Animal]) {}
6.逆变
和协变相反,协变是允许把子类当做父类使用。而逆变则是允许将父类当做子类来使用。
还是上面的例子,这里将父类子类反过来使用。
class Animal() {}
class Cat() extends Animal {}
class ListData[-T] {}
val data2 = new ListData[Animal]()
val data3: ListData[Cat] = data2
def getAnimal(animal: ListData[Cat]) {}
getAnimal(new ListData[Cat]())
7.类型边界
7.1上界
类型边界,这里需要与协变与逆变区分开,他们含义相似,但在使用上不一样。
类型界限与传参的时的继承关系无关,他是指定了该泛型在使用时,泛型的范围。
如下例,定义了ListData的泛型必须为cat或者cat的子类型。这里定义一个ListData[Animal]就会报错
class Animal() {}
class Cat() extends Animal {}
class ListData[T<:Cat] {}
val data2 = new ListData[Animal]() // 报错
7.2 下界
与