目录
泛型类
泛型类,顾名思义,其实就是在类的声明中,定义一些泛型类型,然后在类内部,比如field或者method,就可以使用这些泛型类型。使用泛型类,通常是需要对类中的某些成员,比如某些field和method中的参数或变量,进行统一的类型限制,这样可以保证程序更好的健壮性和稳定性。如果不使用泛型进行统一的类型限制,那么在后期程序运行过程中,难免会出现问题,比如传入了不希望的类型,导致程序出问题。在使用类的时候,比如创建类的对象,将类型参数替换为实际的类型,即可。Scala自动推断泛型类型特性:直接给使用了泛型类型的field赋值时,Scala会自动进行类型推断。
泛型函数
泛型函数,与泛型类类似,可以给某个函数在声明时指定泛型类型,然后在函数体内,多个变量或者返回值之间,就可以使用泛型类型进行声明,从而对某个特殊的变量,或者多个变量,进行强制性的类型限制。与泛型类一样,你可以通过给使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型,也可以在调用函数时,手动指定泛型类型。
上下边界Bounds
在指定泛型类型的时候,有时,我们需要对泛型类型的范围进行界定,而不是可以是任意的类型。比如,我们可能要求某个泛型类型,它就必须是某个类的子类,这样在程序中就可以放心地调用泛型类型继承的父类的方法,程序才能正常的使用和运行。此时就可以使用上下边界Bounds的特性。Scala的上下边界特性允许泛型类型必须是某个类的子类,或者必须是某个类的父类。
上边界用“<:”,下边界用“>:”。这里可以这样记,父类表示大,子类表示小:
T<:S,T小于S,所以T必须是S的子类;
T>:S,T大于S,所以T必须是S的父类。
View Bounds
上下边界Bounds,虽然可以让一种泛型类型,支持有父子关系的多种类型。但是,在某个类与上下边界Bounds指定的父子类型范围内的类都没有任何关系,则默认是肯定不能接受的。然而,View Bounds作为一种上下边界Bounds的加强版,支持可以对类型进行隐式转换,将指定的类型进行隐式转换后,再判断是否在边界指定的类型范围内。
Context Bounds
Context Bounds是一种特殊的Bounds,它会根据泛型类型的声明,比如“T: 类型”要求必须存在一个类型为“类型[T]”的隐式值。
Manifest Context Bounds
在Scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds。也就是说,如果数组元素类型为T的话,需要为类或者函数定义[T: Manifest]泛型类型,这样才能实例化Array[T]这种泛型数组。
协变和逆变
举例来说,Java中,如果有Grandfather是Father的父类,那么Card[Grandfather]是不是Card[Father]的父类?答案是:不是。因此对于开发程序造成了很多的麻烦。
而Scala中,只要灵活使用协变和逆变,就可以解决Java泛型的问题。
协变:[+T],类似上边界 S <: T
逆变:[-T],类似下边界 S >: T
总结
上下边界Bounds,是父类与子类之间的类型界定,使用"<:",">:"
View Bounds,是两个独立类型转换后的边界界定,使用“<%”,">%"
Context Bounds,是隐式烈性嵌套类型“T:M”,"参数:M[T]"
Manifest Context Bounds,是泛型数组,“[T: Manifest]”
协变逆变,对象的泛型有着继承层级关系,那么这个对象也变得有继承层级关系,协变:[+T],类似上边界 S <: T,逆变:[-T],类似下边界 S >: T