泛型类是将类型作为参数的类。它们对于集合类特别有用。
定义泛型类
泛型类在方括号 []
中将类型作为参数。一种约定是使用字母 A
作为类型参数标识符,尽管可以使用任何参数名称。
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
}
}
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
此 Stack
类的实现将任何类型 A
作为参数。这意味着底层列表 var elements: List[A] = Nil
只能存储类型 A
的元素。过程 def push
只接受类型 A
的对象(注意:elements = x :: elements
将 elements
重新分配给一个新列表,该列表通过将 x
前置到当前 elements
来创建)。
此处的 Nil
是一个空的 List
,不要与 null
混淆。
用法
要使用泛型类,请将类型放在方括号中,代替 A
。
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop()) // prints 2
println(stack.pop()) // prints 1
val stack = Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop()) // prints 2
println(stack.pop()) // prints 1
实例 stack
只能采用 Int。但是,如果类型参数具有子类型,则可以传入子类型
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 Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = Stack[Fruit]
val apple = Apple()
val banana = Banana()
stack.push(apple)
stack.push(banana)
类 Apple
和 Banana
均扩展 Fruit
,因此我们可以将实例 apple
和 banana
推送到 Fruit
的堆栈中。
注意:泛型类型的子类型是 *不变的*。这意味着,如果我们具有类型为 Stack[Char]
的字符堆栈,则不能将其用作类型为 Stack[Int]
的整数堆栈。这将是不合理的,因为它会使我们能够在字符堆栈中输入真正的整数。总之,仅当且仅当 B = A
时,Stack[A]
才为 Stack[B]
的子类型。由于这可能相当具有限制性,因此 Scala 提供了一个 类型参数注释机制 来控制泛型类型的子类型行为。