类型参数骑士就是Java中的泛型,比如我们有List a = new ArrayList(),接着a.add(1),没问题,a.add(“2”),然后我们a.get(1) == 2,对不对?肯定不对了,a.get(1)获取的其实是个String——“2”,String——"2"怎么可能与一个Integer类型的2相等呢?
所以Java中提出了泛型的概念,其实也就是类型参数的概念,此时可以用泛型创建List,Listt a = new ArrayList(),那么,此时a.add(1)没问题,而a.add(“2”)呢?就不行了,因为泛型会限制,只能往集合中添加Integer类型,这样就避免了上述的问题。
那么Scala的类型参数是什么?其实意思与Java的泛型是一样的,也是定义一种类型参数,比如在集合,在类,在函数中,定义类型参数,然后就可以保证使用到该类型参数的地方,就肯定,也只能是这种类型。从而实现程序更好的健壮性。
泛型类
其实就是在类中声明,定义一些泛型类型,然后再类内部比如field和method就可以使用这些泛型
使用泛型类通常是需要对类中的某些成员比如某些field和method中的参数或变量,进行统一的类型限制,这样可以保证程序更好地健壮性和稳定性
在使用类的时候比如创建类的对象将类型参数提黄伟事迹的类型即可
scala自动推断泛型特征:直接给使用了泛型类型的field赋值时,scala会自动进行类型推断
案例:新生报到,每个学生来自不同的地方,id可能是Int,可能是String
class Student[T](val localId: T) {
def getSchoolId(hukouId: T) = "S-" + hukouId + "-" + localId
}
val leo = new Student[Int](111)
泛型函数
泛型函数与泛型类类似,可以给某个函数在声明时指定泛型类型,然后在函数体内多个变量或返回值之间就可以使用泛型进行声明,从而对某个特殊的变量或者多个变量进行强制的类型限制
与繁星一样,你可以一个给使用了泛型类型的变量传递至来让scala自动推断泛型的实际类型,也可以在调用函数时手动指定泛型类型
卡片售卖机,可以指定卡片的内容,内容可以是String类型或Int类型
def getCard[T](content: T) = {
if(content.isInstanceOf[Int]) "int card, " + content
else if(content.isInstanceOf[String]) "string card , " + content
else "card: " + content
}
getCard[String]("hello world")
上边界Bounds
在指定反省的时候优势我们需要对泛型类型进行界定,而不是可以任意的类型,比如我们可以要求某个泛型的类型,他就时某个类的之类这样程序中就可以放心的使用泛型类型继承的父类的方法,程序才可以正常的运行,此时就可以使用上下边界Bounds的特性
scala的上下边界特性允许泛型类型必须是某个类的子类,或者必须是某个类的父类
上边界:泛型类型是某个类的子类或者本身这个类
下边界:泛型类型是某个类的父类或者本身这个类
在派对上交朋友
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 Party[T <: Person](p1: T, p2: T) {
def play = p1.makeFriends(p2)
}**
下边界Bounds
案例:领身份证
class Father(val name: String)
class Child(name: String) extends Father(name)
**def getIDCard[R >: Child](person: R)** {
if (person.getClass == classOf[Child]) println("please tell us your parents' names.")
else if (person.getClass == classOf[Father]) println("sign your name for your child's id card.")
else println("sorry, you are not allowed to get id card.")
}
view bounds(视图边界)
上下边界bounds虽然可以让一种泛型类型支持有父子关系的多种类型,但是在某个类与上下边界bounds指定的父子类型范围内的类都没有任何关系,则默认是肯定不能接受的
然而view 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)
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){
def play = p1.makeFriends(p2)
}
val wang = new Student_17_5("wang")
val xiaohuang = new Dog_17_5("xiaohuang")
val p = new Party_17_5(wang,xiaohuang)
context bounds
context bounds是一种特殊的bounds,他会根据泛型类型的声明比如“T: 类型”要求必须存在一个类型为“类型[T]”的隐式值。
案例:使用Scala内置的比较器比较大小
class Calculator[T: Ordering] (val number1: T, val number2: T) {
def max(implicit order: Ordering[T]) = if(order.compare(number1, number2) > 0) number1 else number2
}
Manifest Context Bounds
在scala中如果要实例化泛型数组,就必须使用manifest context bounds,也就是说如果数组元素类型为T的话,需要为类或者函数定义[T:manifest]泛型类型,这样才能实例化Array[T]这种泛型数组
案例:打包饭菜(一种食品打成一包)
class Meat(val name: String)
class Vegetable(val name: String)
def packageFood[T: Manifest] (food: T*):Array[T] = {
val foodPackage = new Array[T](food.length)
for(i <- 0 until food.length) foodPackage(i) = food(i)
foodPackage
}
协变与逆变
scala的协变与逆变非常有特色,完全解决了Java泛型的一大缺憾
举例:Java中如果有professional是master的子类,那么card[professional]是不是card[master]的子类?当然不是
二scala中只要灵活使用协变与逆变就可以解决Java泛型的问题
案例:进入会场
class Master
class Professional extends Master
// 大师以及大师级别以下的名片都可以进入会场
class Card[+T] (val name: String)
def enterMeet(card: Card[Master]) {
println("welcome to have this meeting!")
}
***协变(Cart[Master]是Cart[[Professional]的父类)***
// 只要专家级别的名片就可以进入会场,如果大师级别的过来了,当然可以了!
class Card[-T] (val name: String)
def enterMeet(card: Card[Professional]) {
println("welcome to have this meeting!")
}
逆变Cart[Master]是Cart[[Professional]的子类
Existential Type
在Scala里,有一种特殊的类型参数,就是Existential Type,存在性类型。这种类型务必掌握是什么意思,因为在spark源码实在是太常见了!
Array[T] forSome { type T }
Array[_]