Scala中的类型参数类似于Java中的泛型。在Java中,比如有List a = new ArrayList(),接着a.add(1),a.add(“2”),然后a.get(1) == 2就不对了,因为a.get(1)获取的是一个字符串String–“2”.
所以Java提出了泛型的概念,用泛型创建List,List a = new ArrayList[Integer](),这样创建之后,a.add(1)没问题,a.add(“2”)就不行了。因为泛型限制只能往集合中添加Integer类型。
//就是在类的声明中,定义一些泛型类型,然后在类内部,比如field或者method,就可以使用这些泛型类型。
//使用泛型类,通常是需要对类中的某些成员,比如某些field和method中的参数或变量,进行统一 的类型限制,这样可以保证程序更好的健壮性和稳定性。
//在使用类的时候,比如创建类的对象,将类型参数替换为实际的类型,即可。
//Scala自动推断泛型类型特性:直接给使用了泛型类型的field赋值时,Scala会自动进行类型推断。
案例:新生报到,每个学生来自不同的地方,id可能是Int,可能是String
class Student[T](val localId:T){
def getSchoolId(hukouId:T) = "S-" + hukouId + "-" + localId
}
调用:
val xiaoming = new Student[Int](111)
xiaoming.getSchoolId(222)
与泛型类相同
案例:卡片售卖机,可以指定卡片的内容,内容可以是String类型或Int类型
def getCard[T](content:T) = {
if(content.isInstanceOf[Int]) println("card:this is normal card " + content)
else if(content.isInstanceOf[String]) println("card:this is string card " + content)
else println("card: " + content)
}
调用:
getCard[Int](111)
getCard[Int]("111") //错误
//在指定泛型类型的时候,有时,我们需要对泛型类型的范围进行界定,而不是可以是任意类型。比如,我们可能要求某个泛型类型,它必须是某个类的子类,这样在程序中就可以放心的调用泛型类型继承的父类的方法,程序才能正常的使用和运行。
//Scala的上下边界特性允许泛型类型必须是某个类的子类,或者必须是某个类的父类。
案例:交朋友
class Preson(val name:String){
def sayHello = println("Hello,I'm " + name)
def makefriends(p:Person){
sayHello
p.sayHello
}
}
class Student(name:String) extends Person(name)
class Party[T <: Person](p1:T,p2:T){ //限定传入的对象必须是Person类的对象或者Person类的子类的对象
def play = p1.makeFriends(p2)
}
调用:
val xiaoming = new Student("xiaojming")
val laowang = new Student("laowang")
val party = new Party(xiaoming,laowang)
party.play
//指定下边界,即指定泛型类型必须是某个类的父类
案例:领身份证
class Father(val name:String)
class Child(name:String) extends Father(name)
def getIdCard[T >: Child](p:T){
if(p.getClass == classOf[Child]) pringln("please tell us your parents's names")
else if(p.getClass == classOf[Father]) println("please sign your name and tell us your child's lost id card")
else println("sorry,you are not alloe to get this id card")
}
调用:
val xiaoming = new Father("xiaoming")
val laownag = new Child("laowang")
getIdCard(xiaoming)
View Bounds作为一种上下边界Bounds的加强版,支持可以对类型进行隐式转换,将指定的类型进行隐式转换后,再判断是否在边界指定的类型范围内。
案例:跟小狗交朋友
class Person(val name:String){
def sayHello = println("Hello,I'm " + name)
def makeFriends(p:Person){
sayHello
p.sayHello
}
}
class Student(name:String) extends Person(name)
class Dog(val name:String){
def sayHello = println("Wang,wang,I'm " + name)
}
implicit def dog2person(dog:Object):Person = if(dog.isInstanceOf[Dog]){val _dog = dog.asInstanceOf[Dog];new Person(_dog.name)} else Nil
class Party[T <% Person](p1:T,p2:T)
Context Bounds是一种特殊的Bounds,它会根据泛型类型的声明,比如”T:类型“要求必须存在一个类型为"类型[T]"的隐式值。其实Context Bounds之所以叫Context,是因为它基于的是一种全局的上下文,需要使用到上下文中的隐式值以及注入。
案例:使用Scala内置的比较器比较大小。
class Calculator[T:Ordering](val number1:T,val number2:T){
def max(implicit ordering[T]) = if(order.compare(number1,number2) > 0) number1 else number2
}
在Scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds。也就是说,如果数组元素类型为T的话,需要为类或者函数定义[T:Manifest]泛型类型,这样才能实例化Array[T]这种泛型数组。
案例:打包饭菜(一种食品打成一包)
class Meat(val name:String)
class Vegetable(val name:String)
def pakeageFood(T:Manifest)(food:T*) = { //定义泛型类型,变长参数
val foodPackage = new Array[T](food.length)
for(i <- 0 until food.length) foodPackage(i) = food(i)
foodPackage
}
调用:
val gongbaojiding = new Meat("gongbaojiding")
val yuxiangrousi = new Meat("yuxiangrousi")
val shousibaocai = new Meat("shousibaocai")
val meatPackage = packageFood(gongbaojiding,yuxiangrousi,shousibaocai)
Scala的协变和逆变是非常有特色的,完全解决了Java中的泛型的一大缺陷
举例来说,Java中,如果有Professional是Master的子类,那么Card[Perfessionnal]并不是Card[Master]的子类,这就会对开发程序造成很多的麻烦
案例:进入会场
class Master
class Professionnal extends Master
//大师以及大师级别以下的名片都可以进入会场(向下包容)
class Card[+T](val name:String) //如果Master是Proffessionnal的父类,那么Card[Master]也是Card[Professionnal]的父类
def enterMeet(card:Card[Master]){
println("Welcome to have this meeting")
}
//只要专家级别的名片就可以进入会场,如果大师级别的过来了,当然可以了(向上包容)
class Crad[-T](val name:String) //如果Master是Professionnal的子类,那么Card[Professionnal]也是Card[Master]的子类
def enterMeet(card:Card[Professionnal]){
println("Welcome to have this meeting")
}
Array[T] forSome{type T}
Array[_]