1.泛型类
泛型类,就是在类的声明中定义一些泛型类型,然后再类内部(field、method)就可以使用这些泛型类型
使用泛型类,通常是需要对类中的某些成员,比如method中的参数,field,进行统一的类型限制,这样可以保证程序健壮性
泛型类的使用,如创建类对象,将类型参数替换为实际类型。 或者直接给使用了泛型类型的field赋值,scala会自动类型推断。
案例:
//指定泛型类T,并统一参数localID和hukouID的类型
class Student[T](val localID: T){
def getSchoolID(hukouID: T) = "S-" + hukouID + "-"+localID
}
object Score extends App{
//当new Student时指定泛型类型为Int, local,hukouID都要求传入Int类型
//val cys = new Student[Int]("100001") 传入String报错
val cys = new Student[Int](100001)
cys.getSchoolID(1003)
}
2.泛型函数
可以在给某个函数声明时指定泛型类型,然后在函数体内变量也可以用泛型声明,从而对内部变量进行强制性的类型限制。
案例:
object Score extends App{
//限定函数泛型类型为T
def getCard[T](content: T)={
if(content.isInstanceOf[Int])"card: 001, "+ content
else if(content.isInstanceOf[String]) "card: this is your card, " + content
else "card: " + content
}
getCard[Int](2)
//使用时自动类型推断
getCard(0124)
getCard("sxljg")
}
3.上边界Bounds
在指定泛型类型的时候,有时候需要对泛型类型的范围进行限定,而不是可以任意指定类型。比如,要求某个泛型必须是某个类的子类,这样在程序中调用泛型类型继承的父类方法就可正常使用。此时可使用泛型的上下边界Bounds特性。
案例:
object Score extends App{
class Person(val name:String){
def sayHello = println("Hello, I'm " + name)
def makeFriends(p: Person): Unit ={
sayHello
p.sayHello
}
}
class Student(name:String) extends Person(name)
//通过<:指定 泛型类型必须为Person的子类,从而内部方法play中p1才可调用makeFriends方法,如果传入其他类型报错
class Party[T <: Person](p1: T, p2: T){
def play = p1.makeFriends(p2)
}
val cys = new Student("cys")
val joe = new Student("joe")
val party = new Party[Student](cys,joe)
party.play
}
4.下边界Bounds
指定泛型类型必须为某个类的父类
案例:
object Score extends App{
class Father(val name: String)
class Son(name:String) extends Father(name)
//通过>:指定泛型类型必须为某个类的父类
def getIDCard[T >: Son](person: T): Unit ={
if(person.getClass == classOf[Son]) println("this is you ID card")
else if(person.getClass == classOf[Father] ) println("this is you son's ID card")
else println("sorry, you are not allowed to get ID card.")
}
val father = new Father("cys")
val son = new Son("joe")
getIDCard(son)
getIDCard(father)
}
5.View Bounds
上下边界Bounds虽然可以限制泛型类型的上下边界在父子关系内,但是当某个类超出了泛型定义的上下边界内时,默认不可接收。比如,案例4中,若存在Dog类,则party类无法传入dog类对象作为参数;
View Bounds可以扩充上下边界,通过对类型的隐式转换,将指定类型进行隐式转换后,再判断是否在边界指定范围内。
案例:
object Score extends App {
class Person(val name: String) {
def sayHello = println("Hello, I'm " + name)
def makeFriends(p: Person): Unit = {
sayHello
p.sayHello
}
}
class Student(name: String) extends Person(name)
class Dog(val name: String) {
def sayHello = println("wangwangwang")
}
implicit def dog2Person(dog: Object): Person = {
if (dog.isInstanceOf[Dog]) {
//传入的dog时object类型,需转为Dog类型,再调用name
val _dog = dog.asInstanceOf[Dog]
new Person(_dog.name)
} else
//Nil idea提示错误,但不影响编译运行
Nil
}
//支持通过隐式类型转换后,再判断边界范围
class Party[T <% Person](p1: T, p2: T){
def play(p1: Person,p2: Person): Unit ={
p1.makeFriends(p2)
}
}
val cys = new Student("cys")
val dog = new Dog("wangcai")
val party = new Party[Person](cys,dog)
party.play(cys,dog)
}
6.Context Bounds
contextBounds 会根据泛型类型的声明【T:类型】,在上下文中查找一个类型为【类型[T]】的隐式值
object Score extends App {
class Calculator[T: Ordering](val num1: T, val num2: T){
//隐式参数order
def max(implicit order: Ordering[T]) = if (order.compare(num1,num2) > 0) num1 else num2
//max的另一种写法
def max2 = {
val order = implicitly[Ordering[T]]
if (order.compare(num1,num2) > 0)
num1
else
num2
}
}
val c = new Calculator(1,2)
c.max
c.max2
}
7.Manifest context Bounds
在scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds,即如果数组元素类型为[T],则类或函数需要定义[T:Manifest]泛型类型,这样才能实例化Array[T]。
object Score extends App {
class Meat(val name: String)
class Vegetable(val name: String)
def packageFood[T:Manifest](food: T*)={
val foodPackage = new Array[T](food.length)
for (i <- 0 until food.length) {
foodPackage(i) = food(i)
food(i)
}
foodPackage
}
println(packageFood(new Meat("hongshaorou"),new Meat("niurou")).getClass) // class [LscoreTest.Score$Meat;
}
8.协变和逆变
在java中 如果有Professional是Master的子类,那么Card[Profession]是不是Card[Master]的子类,答案:不是。这样就造成,
(1) 当某一个函数指定了接收参数类型为Card[Master]时,Card[Professional]无法作为参数传入,解决这个问题叫协变[+T];
(2) 当函数指定接收参数类型为Card[Professional]时,使得Card[Master]也能作为参数传入,为逆变。
但在scala中可通过协变与逆变解决这个问题。
object Score extends App {
class Master
class Professional extends Master
//
class Card[+T](val name:String)
def enterMeeting(card: Card[Master]): Unit ={
println("welcome attending conference, " + card.name)
}
val cys = new Card[Master]("cys")
val joe = new Card[Professional]("joe")
//如果enterMeeting() 接收的是card: Card[Professional],那么会有类型异常
enterMeeting(cys)
//enterMeeting原本接收的是Card[Master],但是通过[+T]使子类professional允许进入
enterMeeting(joe)
//逆变:通过[-T]允许父类进入
/* class Card[-T](val name: String)
def enterMeeting(card: Professional) ={
println("welcome attending conference")
}*/
}