Scala的泛型
泛型介绍:泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效 地增强程序的适用性,使用泛型可以使得类或方法具有更强的通用性。泛型的典型应用场景 是集合及集合中的方法参数。
泛型方法:指定方法可以接受任意类型参数。
泛型类:指定类可以接受任意类型参数。
例:
object GenericTypeTest01 {def main(args: Array[String]): Unit = {println(new Student11[String,Int]("黄渤",33).name)println(new Student12[String,Int]("zs",18).name)println(new Student22[String,Int]("zs",8).age) }}class Student12[T,S](var name:T,var age:S){}class Student11[T,S](var name:T, var age:S){}class Person11[T](var name:T)class Student22[T,S](name:T,var age:S) extends Person11(name) {}
1. scala类型变量界定
类型变量界定是指在泛型的基础上,对泛型的范围进行进一步的界定,从而缩小泛型的具体范围。
例:
object Test01 { def main(args: Array[String]): Unit = { var generic=new Generic val result: Int = generic.compare("aa","bb") }}class Generic{ /** *T<:Comparable 表示compare方法中如果输入的类型处于Comparable类对应的继承体系中,则是合法的,否则编译不通过 * 作用是:当调用泛型的方法是,但是不知道这个泛型是否有这个方法,此时使用泛型的类型变量界定,缩写范围,使得,泛型中有这个方法 */ def compare[T<:Comparable[T]](first:T,second:T)={ val result=if(first.compareTo(second)>0) 1 else 0 result }}
2. scala视图界定
类型变量界定建立在类继承的层次上,但有时候这种限定不能满足实际要求,如果希望跨越类继承层次结构时,可以使用视图界定来实现,原理是通过隐式转换来实现。
隐含参数和方法也可以定义隐式转换,称作视图。视图的绑定从另一个角度看就是 implicit 的转换。其实视图的绑定就是为了更方便的使用隐式转化,视图界定利用<%符号来实现。
例:
object Test01 { def main(args: Array[String]): Unit = { var ann1 = new Animals("zs", "18") var ann2 = new Animals("zs", 18) }}case class Animals[T, S <: Comparable[S]](var name: T, var age: S)
此时如果在[T, S <: Comparable[S]]使用<:的话,在运行的时候会报错
因为:在类型变量界定的使用,默认的只能界定的类的是继承体系中的一员才成立,如果是使用隐式转换的方式默认不成立。上面代码:String类继承了Comparable,但是Int没有继承Comparable,只是隐式的将Int转换成了RichInt,RichInt继承了Comparable,所以此处出现了错误。
如果想隐式转换也可以通过泛型的话可以:
object Test01 { def main(args: Array[String]): Unit = { var ann1 = new Animals("zs", "18") var ann2 = new Animals("zs", 18) }}case class Animals[T, S <% Comparable[S]](var name: T, var age:
利用<%号对泛型 S 进行限定,它的意思是 S 可以是 Comparable 类继承层次结构中实现了 Comparable 接口的类,也可以是能够经过隐式转换得到的实现了 Comparable 接口的类。
在指定泛型类型时,有时需要界定泛型类型的范围,而不是接收任意类型。比如,要求某个 泛型类型,必须是某个类的子类,这样在程序中就可以放心的调用父类的方法,程序才能正 常的使用与运行。此时,就可以使用上下边界 Bounds 的特性; Scala 的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类。
U>:T这是类型下界的定义,也就是 U 必须是类型 T 的父类(或本身,自己也可以认为是自己的父 类)。
S<:T这是类型上界的定义,也就是 S 必须是类型 T 的子类(或本身,自己也可以认为是自己的子 类)。
上界:
class Generic2{//指定上界,T必须是Comparable的子类或者是Comparabledef compare[T<:Comparable[T]] (first:T,second:T) ={ }}
下界:
class Generic3{//指定下界,T必须是Comparable的父类或者是Comparabledef compare[T>:Comparable[T]] (first:T,second:T) ={ }}
4. scala逆变和逆变协变
协变定义形式如:trait List[+T]{}
当类型 B 是类型 A 的子类型时,则 List[B]也可以认为是 List[A}的子类型,即 List[B]可以泛化 为 List[A]。也就是被参数化类型的泛化方向与参数类型的方向是一致的,所以称为协变 (covariance)
例:
object Test01 {def main(args: Array[String]): Unit = {var list1:MyList[Person]=new MyList(new Person)var list2:MyList[Son]=new MyList(new Son)list1=list2}}class Personclass Son extends Personclass MyList[+T](val value:T)
这种方式,在list中只能将子类转化成为父类的list,如果在转变之后,这个list中也只能存放子类的类型对象。协变的性质:输入的类型必须是 Son 的超类。
逆变
逆变定义形式如:trait List[-T]{}
当类型 B 是类型 A 的子类型,则 Queue[A]反过来可以认为是 Queue[B}的子类型。也就是被参数化类型的泛化方向与参数类型的方向是相反的,所以称为逆变(contravariance)。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。