scala的泛型

15 阅读3分钟

(一)问题导入

需求定义一个名为getMiddleElement的方法,用它来获取输入列表的中间位置上的元素

def main(args: Array[String]): Unit = {  
  val arr1 = Array(1,2,3,4,5)  
  def getMiddleEle(arr:Array[Int]): Int = {  
    arr(arr.length/2)  
  }  
  val i:Int = getMiddleEle(arr1)  
  println(i)  
}

新的需求:如果来了一个新的列表,它保存的是字符串类型的列表,大家应该如如何去实现这个功能呢? 可以定义这个同名的方法?

def getMiddleEle(arr:Array[Int]): Int = {

    arr(arr.length/2)

}

def getMiddleEle(arr:Array[String]): String = {

    arr(arr.length/2)

}

答案是:不行。错误的原因是:函数同名了

那可以改下函数,把函数换个名字吗? 当然可以的,但是,这样就太浪费了。

此时我们遇到的困难是: 类型是变化的! 这里就可以使用泛型改进:使用泛型来定义。

(二)泛型的概念

泛型的定义为:参数化类型,即所有操作的数据类型被指定为一个参数。

在Scala中,用[]表示(在java中使用<>)

package fx
/*
*
*  泛型函数:
*
*  getMiddle(Array(1,2,3,4,5))  ===>3
*
*
*  getMiddle(Array("1","2","3","4","5"))   ===>3
*
*
* */

object fx01 {

  def getMidlle_Int(arr:Array[Int]):Int = {
    // 长度/2
    arr(arr.length / 2)
  }

  def getMiddle_String(arr: Array[String]):String = {
    // 长度/2
    arr(arr.length / 2)
  }

  def getMiddle_Double(arr: Array[Double]): Double = {
    // 长度/2
    arr(arr.length / 2)
  }

  def main(args: Array[String]): Unit = {

    var m = getMidlle_Int(Array(1,2,3,4,5))

    println(s"数组的中间元素是:${m}")

    var m1 = getMiddle_String(Array("aa","bb","cc"))

    println(s"数组的中间元素是:${m1}")

    var m2 = getMiddle_Double(Array(1.1,2.2,3.3))

    println(s"数组的中间元素是:${m2}")


  }
}

(二)泛型方法

泛型方法指的是:把泛型定义放在方法声明上。即:该方法的参数类型是由泛型来决定的。在调用方法时,明确具体的数据类型。

(三)泛型方法的格式

定义方法: def 方法名泛型名称1,泛型名称2,. . . = {  }

调用方法: 方法名类型1,类型2,

如果在参数列表中可以推断出对应的类型,则可以省略方括号[类型1,类型2]

package fx
/*
*
*
*
*  getMiddle(Array(1,2,3,4,5))  ===>3
*
*
*  getMiddle(Array("1","2","3","4","5"))   ===>3
*
*
* */

object fx02 {

  def getMiddle[T](arr: Array[T]): T = {
    // 长度/2
    arr(arr.length / 2)
  }

  def main(args: Array[String]): Unit = {

    var m = getMiddle[Int](Array(1,2,3,4,5))
    println(s"数组的中间元素是:${m}")

    var m1 = getMiddle[String](Array("aa","bb","cc"))
    println(s"数组的中间元素是:${m1}")

    var m2 = getMiddle[Double](Array(1.1,2.2,3.3))
    println(s"数组的中间元素是:${m2}")

    var m3 = getMiddle[Boolean](Array(true,false,true))
    println(s"数组的中间元素是:${m3}")


  }
}

(四)理解泛型

泛型和数据类型有什么区别:

case class Student()

val s1 = Student()

val list = ArrayList[Student]()

list += s1
ArrayList 是数据类型Student是泛型。 他们不是一个层次的概念。 类型内部的数据使用泛型来约束。

2、泛型的声明方式是从外部把类型传入到类的内部,好比是传入参数一样。所以,泛型也称之为类型参数。如果参数没有传递,就说明不需要类型的约束,它也不会发生错误。而是采用通用类型。

3、在编译时有效,在运行时会失效。也就是说在代码被编译之后,在产生的代码中是看不到泛型相关的代码的。

package fx

/*
*
* 定义集合(set,list,map,array)时,通过泛型来传递可以装入的数据类型
*
* */

object fx03 {


  def main(args: Array[String]): Unit = {
    var li = scala.collection.mutable.ListBuffer[Int]()
    li += 1
    li += 2

    li.foreach(println)

  }
}

(五)泛型类

泛型类指的是:把泛型定义放在类的声明上。即:该类中的参数类型是由泛型来决定的。在创建对象的时候,再来明确具体的数据类型。

格式:class 类[T](val 变量:T)

来从一个具体的需求出发来看看泛型类的使用。

需求:定义一个Pair泛型类,该类包含两个字段,且两个字段的类型不固定。创建不同类型的Pair泛型类对象,并打印

例1:

package fx
/*
*
*泛型类:
*  类内部的数据类型不确定,所以用泛型
*
* */
object fx04 {

  class Pair[T] (var a:T,var b:T)


  def main(args: Array[String]): Unit = {
    val p1 = new Pair[Int](1,2)
    println(p1.a)
    println(p1.b)

    val p2 = new Pair[Double](1.1,2.2)
    println(p2.a)
    println(p2.b)


  }
}

【写泛型类的步骤格式:先写一个普通的类 -> 把参数的类型(或者返回值的类型,或者内部属性成员的类型)改成泛型名 -> 在类名的后面添加[泛型]】

例2:

泛型特质

泛型特质指的是:把泛型定义放在trait的声明上。即:该特质中的参数类型是由泛型来决定的。在定义特质的子类或者子单例对象时,明确具体的数据类型。

【格式】

trait 特质A[T] {}

class B extends 特质A[指定的数据类型] {}

需求

1、定义泛型特质Logger,该特质有一个变量a和show方法,他们都是用Logger特质的泛型。

2、定义单例对象ConsoleLogger继承Logger特质