先看一段代码
object testClassTag {
def main(args: Array[String]): Unit = {
val arr = createArray(1,2)
println(arr.mkString(","))
}
def createArray[T](one: T, two: T) = {
// 创建以一个数组 并赋值
val arr = new Array[T](2) //期望根据T的类型动态生成不同数据类型的数组
arr(0) = one
arr(1) = two
arr
}
}
这段代码的目的是想传入两个参数,然后使用这两个参数初始化该数组,并且可以根据参数数据类型来动态生成不同的数据类型数组,IDE没有报错,说明没有语法错误,但是编译运行就会报错
cannot find class tag for element type T
val r = new Array[T](2)
错误提示看起来是代码运行的时候找不到这个T的类型,为什么找不到呢?这里面就涉及到 jvm的类型擦除问题,类Java语言只能在编译的阶段获取到类型参数,一旦代码被送入JVM运行,T的类型信息就被擦除了,但有人要问了,为什么下面这样使用泛型却不会报错
object testSpark {
def main(args: Array[String]): Unit = {
var res = new getMessage(10) {}
println(res.get())
}
}
abstract class getMessage[T](var param:T){
def get():T = {
param
}
}
这段代码在运行的时候,函数体内只有参数本身,并没有涉及T类型
这就得出一个很粗暴的结论,怎么区分泛型在哪些场合下会被类型擦除,我的总结就是只要方法体或函数体内包含了T,K,V此类泛型标识,必然会有类型擦除。
- 有没有办法可以不让类型被擦除呢,这个时候 ClassTag 就要上场了
import scala.reflect.ClassTag
object testClassTag {
def main(args: Array[String]): Unit = {
val arr = createArray(1,2)
println(arr.mkString(","))
}
def createArray[T:ClassTag](one: T, two: T) = {
// 创建以一个数组 并赋值
val arr = new Array[T](2) //期望根据T的类型动态生成不同数据类型的数组
arr(0) = one
arr(1) = two
arr
}
}
1.只要在定义泛型函数或泛型类的时候,在泛型标识后加上:ClassTag关键字,并且导入 scala.reflect.ClassTag 包即可
2.或者使用:Manifest关键字,这个不需要导包
加上后,发现此时可以动态生成不同数据类型的数组
最后附上一个使用泛型动态生成数组的函数
def createArray[T: Manifest](arr: T*): Array[T] = {
val arrs = new Array[T](arr.length)
for (item <- 0 until arr.length)
arrs(item) = arr(item)
arrs
}