scala类型参数:类似于java中的泛型概念

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")
  }*/

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值