泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效 地增强程序的适用性,使用泛型可以使得类或方法具有更强的通用性。泛型的典型应用场景 是集合及集合中的方法参数。
泛型类实例如下:
object GenreicTypeOps {
def main(args: Array[String]): Unit = {
val product=new ProductDao()
val item=new Product(1234,"黄金",200)
product.insert(item)
}
case class User(name:String, age:Int)
case class Product(pid:Long, name:String, price:Int)
/*泛型类的特质*/
trait BaseDao[T]{
def insert(item:T)
}
class UserDao extends BaseDao[User]{
override def insert(item:User): Unit = {
println(s"向数据库中传入一个用户${item.name},年龄:${item.age}。")
}
}
class ProductDao extends BaseDao[Product]{
override def insert(item: Product): Unit = {
println(s"向数据库中传入一个商品:${item.pid},价格:${item.price}。")
}
}
}
泛型方法实例如下(插入排序):
object GenericmethodOps {
def main(args: Array[String]): Unit = {
val array:Array[Int]=Array(5,18,1,8,19,-9,52,7,3,1)
println("排序前:"+array.mkString("[",",","]"))
insertSort[Int](array)
println("排序后:"+array.mkString("[",",","]"))
}
def insertSort[T <% Comparable[T]](array: Array[T]): Unit = {
for(i <- 1 until array.size) {
for(j <- 1 to i reverse) {
if (array(j).compareTo(array(j-1)) > 0) {
swap(array,j-1,j)
}
}
}
}
def swap[T](array: Array[T],i:Int,j:Int): Unit = {
val tmp=array(i)
array(i)=array(j)
array(j)=tmp
}
}
类型变量上界和下界限定是指在泛型的基础上,对泛型的范围进行进一步的界定,从而缩小泛型的具体范围。比如,要求某个 泛型类型,必须是某个类的子类,这样在程序中就可以放心的调用父类的方法,程序才能正 常的使用与运行。Scala 的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类。具体语法如下:
class GenericTypeTest2 {
def compare[T <: Comparable[T]](first:T,second:T)={
if (first.compareTo(second)>0)
first
else
second
} }
**T <: Comparable[T] **表示泛型 T 的类型的最顶层类是 Comparable,所有输入是 Comparable 的子类都是合法的,其 它的都是非法的,因为被称为上界 。
class A
class B extends A
class C extends B
class D extends C
opt[T >: C]
opt[T >: C]表示 T 的类型只能是 A,B,C 了,不能是 D(其实就是限制了最底层的类型是什么)。在类 的继承结构体系中,从上到下,只能到类型 C 为止 。
上面讲的类型变量界定建立在类继承层次结构的基础上,但有时候这种限定不能满足实际要 求,如果希望跨越类继承层次结构时,可以使用视图界定来实现的,其后面的原理是通过隐 式转换来实现。 隐含参数和方法也可以定义隐式转换,称作视图。视图的绑定从另一个角度看就是 implicit 的转换。主要用在两个场合: 1、当一个 T 类型的变量 t 要装换成 A 类型时;2、当一个类型 T 的变量 t 无法拥有 A 类型的 a 方法或变量时 其实视图的绑定是为了更方便的使用隐式装换 视图界定利用<%符号来实现 (上述插入排序就是这么处理的)。
利用<%符号对泛型 S 进行限定,它的意思是 S 可以是 Comparable 类继承层次结构中实现了 Comparable 接口的类,也可以是能够经过隐式转换得到的实现了 Comparable 接口的类。 上述代码的语句在视图界定中是合法的,因为 Int 类型此时会隐式转换为 RichInt 类,而 RichInt 类属于 Comparable 继承层次结构。Int 类会隐式转换成 RichInt 类,RichInt 并不是直 接实现 Comparable 口,而是通过 ScalaNumberProxy 类将 Comparable 中的方法继承过来。
协变定义形式如:
trait List[+T]{}
当类型 B 是类型 A 的子类型时,则 List[B]也可以认为是 List[A}的子类型,即 List[B]可以泛化 为 List[A]。
逆变定义形式如:
trait List[-T]{}
当类型 B 是类型 A 的子类型,则 List[A]反过来可以认为是 List[B]的子类型。也就是被 参数化类型的泛化方向与参数类型的方向是相反的,所以称为逆变(contravariance) 。