本文链接:Scala学习(五)——泛型
简介
在Java或者C++里面,像列表(List
)这些数据结构,在编写的时候,都不需要指定其中元素的类型,而是构造的时候指定,这一特性就称为泛型。同样,Scala中也提供了泛型,而且功能比Java的泛型更加强大。
类的泛型
可以给一个类添加泛型,这样,在编写的时候就不需要考虑这一类型的具体情况,而是使用一个标记来注明。泛型的定义列表用[]
包含,用,
分隔,卸载类名之后,构造函数参数列表之前,泛型的具体名称可以任意定义(比如如下代码中的K
和V
):
类似构造函数,如果要继承的类包括泛型,那么继承时也需要写泛型的类型:
不过这里Pair
的泛型其实是可以通过构造函数传值的类型猜测出来的,所以可以省略:
这样,类名在声明或者新建实例的时候也需要写明泛型的类型:
当然,上面这句话的最简写法是这样的,可以猜到的类型和泛型设定都被省略掉了:
方法的泛型
除了类可以设置泛型,方法也可以设置泛型。写法是在方法名后面加上泛型列表。下面这个方法完成了任意类型T
数组的赋值操作(没有实际意义):
调用时同样可以显式写明泛型类型或者省略:
泛型的上下界
在定义泛型列表的时候可以使用<:
和>:
规定泛型元素的上下界:
可以使用with
关键字对多个特征进行限定:
协变和逆变
简而言之,协变和逆变是指类型AClass[T]
会随着泛型参数T
的继承关系而产生继承关系。声明时只需要在泛型参数前加+
或者-
就可以获得协变或者逆变特性:
以下的实例说明了协变和逆变的继承关系:
如果不加协变或者逆变的符号,那么:
在使用中,协变用于写,比如作为参数,可以输入其子类,逆变用于读,比如作为函数返回值,可以接受其父类。协变和逆变这一设定,是Java所不具有的,体现了Scala的实用性。
可实例化的泛型
大家都知道Java的泛型并不能实例化,尤其是像List.toArray
这种方法,还需要自己实例化一个相应数组传参进去,不然就只能返回Object
数组。Scala运行在JVM上,也存在这样的问题,不过Scala提供了一种较简便的方法来解决这个问题。下面用一个方法来说明:
这个方法输入一个任意类型的值,输出一个相应的只有一个元素数组。值得注意的是,在泛型参数T
之后增加了:ClassTag
。这一操作使调用函数时,会将泛型的类型信息记录在一个ClassTag
类型的对象里,之后可以通过这个对象调用Java反射构造数组。有关这种写法的意义将在以后说明。
总结
Scala的泛型系统相比Java完善了许多,相比鸡肋一般的Java泛型,Scala泛型的完成度几乎可以媲美C++模板。用好泛型可以使程序可扩展性更强,结构更加严密。