数组在运行时保留其类型,但泛型方法由于类型擦除而在运行时失去其通用性。因此,如果您在运行时从泛型方法动态创建数组,则必须保留泛型类型信息。由于擦除,JVM 不知道类型,但 Scala 以 ClassTag 的形式保留信息,使您可以避免擦除问题。
你可以通过使用 Java 反射来作弊
def y[A](a: A, length: Int) = java.lang.reflect.Array.newInstance(a.getClass, length)
但这会很糟糕 - 请注意,由于擦除,返回的类型是 Object,而不是 Array[A]
scala> y("foo", 1)
res2: Object = Array(null)
另请注意,java.lang.reflect.Array.newInstance() 在API文档 https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Array.html.
这是有道理的,因为 Java 具有擦除功能并且没有 ClassTags。
Scala 有 ClassTags,因此可以使用适当的类型创建在运行时创建的数组:
scala> def y[A : ClassTag](a: A) = Array(a)
y: [A](a: A)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A]
scala> y("foo")
res4: Array[String] = Array(foo)
scala> y(1)
res5: Array[Int] = Array(1)
在此处了解有关 JVM 上的类型擦除的更多信息(Java 示例):
- 删除泛型类型 https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html
-
删除泛型方法 https://docs.oracle.com/javase/tutorial/java/generics/genMethods.html
- 擦除桥接方法 https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html
- 不可具体化的类型 https://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html
当然,由于擦除,A的List在运行时变成了AnyRef的List,因此只要在编译时验证类型检查(通过泛型),JVM在运行时并不关心泛型对象的类型是什么。被实例化。