天天看點

scala 與 java泛型數組

java 泛型數組初始化

public class GenericArray<T> {

    private T[] arr;

    public GenericArray(){
        arr = new T[10]; //編譯錯誤
    }

}
           

使用這樣的方式初始化java的數組會出錯,因為java不支援泛型數組。按照我的了解,java 初始化數組時候,需要知道數組的确切類型,但是泛型是編譯後擦除的。是以運作時,無法知道數組的确切類型。是以java不支援以 new T[] 方式初始化一個數組。

如果想進行初始化,可以通過這樣的方式

T[] arr=(T[]) new Object[10];
           

scala的泛型數組

那麼同樣的場景,在scala中如何實作呢

class ScalaGenericArray[T]{
  val arr: Array[T] = new Array[T](10)
}

object ScalaGenericArray{
  def main(args: Array[String]): Unit = {
    val arr = new ScalaGenericArray[String]
  }
}
           

看起來很自然,但是在運作時候會報錯:

Error:(9, 23) cannot find class tag for element type T

val arr: Array[T] = new Array[T](10)

原因和java的一樣,虛拟機中,泛型相關的類型資訊會被擦除,是以無法将T解釋成實際類型String

那麼如何做呢,此處我們需要将類型的資訊以一個參數的方式傳進去

class ScalaGenericArray[T](implicit classTag:ClassTag[T] ){ //讓編譯器幫我們傳入類型資訊

  val arr: Array[T] = new Array[T](10)

}

object ScalaGenericArray{
  def main(args: Array[String]): Unit = {
    val arr = new ScalaGenericArray[String]
  }
}
           
  1. 感覺這種方式有點類似于java為了擷取一個泛型的資訊,将類以參數的形式傳入函數參數中
public <T> T test(Class<T> clazz) {
        System.out.println(clazz);
        //...
}
           
  1. 當然此處的ClassTag也可以使用Manifest,但是在scala 2.10.0後就不推薦使用了
  2. 這樣寫比較複雜,scala也提供另一種簡單的方式,上下文界定
class ScalaGenericArray[T: ClassTag] {//此處不再需要提供參數
  val arr: Array[T] = new Array[T](10)
}

object ScalaGenericArray {
  def main(args: Array[String]): Unit = {
    val arr = new ScalaGenericArray[String]
  }
}
           

這是scala的文法糖,T:ClassTag 告訴scala存在一個類型為ClassTag[T] 的隐式參數