scala学习第三篇之类型参数(泛型)

概述:类型参数,说白了就是泛型,什么是泛型?广泛的类型,啥类型都有可能,是一种更加通用的表示,或者定义。
Scala中定义泛型的方式和java中稍微有点不同,java中<>,scala中[],其他都一样。

一、类上定义泛型

?:
/**
  * 泛型
  */
object GenericOps {
  def main(args: Array[String]) {
    val tool = new Tool[Int]()
    println(tool.add(1,2))
    println(tool.add(32,54,4,5))

    val tool1 = new Tool[String]()
    println(tool1.add("first","last"))
  }
}

class Tool[T] {
  def add(a:T,b:T) : T = {
    a
  }
  def add(arr:T*):T={
    arr(0)
  }
}

虽然上面定义了泛型类,但是不是很灵活,因为一旦在成员上面使用了这个类的泛型,那么便无法再使用其它类型。

二、方法上定义泛型

?:
object _03GenericOps {
  def main(args: Array[String]) {
    val tool = new Tool[Int]()
    tool.show[String]("show","your","name")
  }
}

class Tool[T] {
  def show[Q](arr:Q*): Unit ={
    println(arr.mkString(","))
  }
}

说明在方法上面使用的泛型,会覆盖掉类上定义的泛型

三、泛型界定和视图界定

Scala中的泛型界/限定的概念和java中的泛型的限定是一样的。
先用例子给大家看看,然后咱们总结一下:

?:
def main(args: Array[String]): Unit = {
    val array = Array[Int](1, 5, 3, 5, 6, 7, 2, 9)
    val strArr = Array[String]("abc", "def", "rst", "lmn")
    println("排序前的数组:" + array.mkString("[", ", ", "]"))
    selectSort(array)
    println("排序后的数组:" + array.mkString("[", ", ", "]"))
    /*
    val aa:Int = 3
    val bb = 4
    aa.compareTo(bb)
    */

def selectSort[T <% Comparable[T]](arr:Array[T]): Unit ={
    for (i <- 0 until arr.length ){
      for (j <- i until arr.length){
        if(arr(i).compareTo(arr(j))>0){
          swap(arr,i,j)
        }
      }
    }
  }

  def swap[T](arr:Array[T],i:Int,j:Int): Unit ={
    var temp = arr(i)
    arr(i) = arr(j)
    arr(j) = temp
  }
  }

总结:
上限限定(掌握)

在java中的语法结构
在scala中语法结构[T <: Xxx]
如果使用通配符的话,用?

下限限定(了解)

在java中的语法结构
在scala中语法结构[T >: Xxx]
通配符用_

在scala中让一个类型具备比较性,一般都是用Ordered[T] --对应–> java中的Comparable[T]
在scala中让一个集合提供比较器,一般都用Ordering[T] --定义–>java中的 Comparator[T]

这里看到,Int类型没有直接扩展Comparable接口,所以我们不能直接对齐进行使用xx.compareTo的操作,也就是说如果类型[T <: Comparable[T]]的,此时T是Int,编译无法通过,但是只要做一下稍微的搞定即可[T <% Comparable[T]],编译就可以通过,当然如果想让之前的代码通过,只需要将Int该成Integer即可。
val aaa:Int = 3
val bb = 4
aaa.compareTo(bb),这个是直接可以进行操作,这和上面Int没有扩展Comparable矛盾,所以肯定在背后有人来帮助
Int做了实现,达到的效果就是对Int做了包装,RichInt extends Comparable[RichInt]
以后但凡出现Int,会自动的转化为RichInt,这个操作就是隐式转化
在定义的使用手动进行类型转化,就用到了scala中视图界定 <%

四、协变和逆变

在Java中泛型的一个特点,在java中规定,=左右两侧的泛型都必须是一致,
其实这就是多态,父类引用指向子类对象

List<Object> list = new ArrayList<Person>();
list.add(new Person());    
list.add(new Student());

List<Person> list2 = new ArrayList<Object>();
list2.add(new Person());
list2.add(new Student());

以上两种操作方式都是错误的,不被允许的。把这种操作称之为泛型的继承。
那么在scal中是如何规定的呢?
scala学习第三篇之类型参数(泛型)_第1张图片
在默认情况下,scala也不允许出现上述泛型继承的现象。
但是非常灵活的scala,在特殊情况下是允许这些情况的方式,也就是对应的协变和逆变。在定义泛型的时候,添加一个符号即可[+T]协变,[-T]逆变。
协变指的是等号左侧的泛型是右侧的超类,逆变指的是等号左侧的泛型是右侧的子类。
多用于集合的操作。

object _04T {
  def main(args: Array[String]) {
    val list1:MyList1[Object] = new MyList1[Person]()
    val list2:MyList2[Person] = new MyList2[Object]()
    val list3:List[Object] = List[Person]()
  }
  class MyList1[+T] { //把这种泛型的继承称之为协变
  }
  class MyList2[-T] {//把这种泛型的继承称之为逆变
  }
}

class Person{
}

你可能感兴趣的:(scala,scala泛型详解,scala类型参数详解,scala泛型实例,scala类型参数实例)