泛型
基本概念
基本概念同 Java。
创建泛型
类型参数使用 [类型参数名]
作为类型的占位符,而 Java 用的是 <>
。
class Capture[A](val a: A) {
}
Scala 中最常用的占位符为 “A”。
使用泛型
val integerCapture = new Capture[Int](10)
val nint10:Int = integerCapture.a
val stringCapture = new Capture[String]("Hi")
val strHi:String = stringCapture.a
println(strHi)
以上分别用 Int
和 String
作为传入的类型参数,如果向这两个对象传入不符合的类型时编译器就会理解报错,此外取数据时也不用进行强制转换,比起没有泛型时要方便很多。
协变与逆变
如果 Capture
注意,函数的参数是逆变的,函数的返回值是协变的。
使用协变
使用协变需要在类型前加上 +
。
定义一个支持协变的类,协变类型参数只能用作输出,所以可以作为返回值类型但是无法作为入参的类型
class CovariantHolder[+A](val a: A) {
def foo(): A = {
a
}
}
使用该类
var strCo = new CovariantHolder[String]("a")
var intCo = new CovariantHolder[Int](3)
var anyCo = new CovariantHolder[AnyRef]("b")
// Wrong!! Int 不是 AnyRef 的子类
// anyCo = intCo
anyCo = strCo
使用逆变
使用逆变需要在类型前加上 -
。
定义一个支持逆变的类,逆变类型参数只能用作输入,所以可以作为入参的类型但是无法作为返回值类型
class ContravarintHolder[-A]() {
def foo(p: A): Unit = {
}
}
使用该类
var strDCo = new ContravarintHolder[String]()
var intDCo = new ContravarintHolder[Int]()
var anyDCo = new ContravarintHolder[AnyRef]()
// Wrong!! AnyRef 不是 Int 的超类
// strDCo = anyDCo
strDCo = anyDCo
类型通配符
概念与 Java 基本一致,只是 Scala 使用 _
作为通配符。
def foo2(capture: Capture[_]): Unit = {
}
类型参数边界
上边界用于限定类型参数一定是某个类的子类,使用符号 <:
指定。下边界用于限定类型参数一定是某个类的超类,使用符号 >:
指定。
上边界无法确定容器中保存的真实类型,所以无法向其中追加数据,但是可以获得边界类型的数据
def foo3(list: collection.mutable.MutableList[_ <: Num]): Unit = {
// list += new Num(4)
val num = list.head
println(num.number)
}
下边界可以追加边界类型的数据,但是获得数据都只能是 Any 类型
def foo4(list: collection.mutable.MutableList[_ >: Num]): Unit = {
list += new Num(4)
val num = list.head
println(num.asInstanceOf[Num].number)
}
最小类型
Scala 中在表示边界时可以使用 Nothing
表示最小类型,即该类为所有类型的子类,所有可以写出以下代码。
def foo5(capture: Capture[_ >: Nothing]): Unit = {
}
项目源码见 JGSK/_27_generics