Java Scala是否可以在不改变JVM的情况下对泛型进行具体化?

Java Scala是否可以在不改变JVM的情况下对泛型进行具体化?,java,generics,scala,jvm,Java,Generics,Scala,Jvm,我最近开始学习Scala,对于它们的泛型也是通过类型擦除实现的,我感到失望(但并不惊讶) 我的问题是,Scala是否有可能对泛型进行具体化,或者JVM是否需要以某种方式进行更改?如果JVM确实需要更改,那么具体需要更改什么?否-如果字节码不支持具体化的泛型,Scala就不可能作为Java等效字节码运行 当你问“需要更改的是什么?”时,答案是:字节码规范。目前字节码不允许定义变量的参数化类型。已经决定,作为对字节码的修改,以支持具体化的泛型,将 为了解决这个问题,Scala利用其隐式机制的强大功能

我最近开始学习Scala,对于它们的泛型也是通过类型擦除实现的,我感到失望(但并不惊讶)


我的问题是,Scala是否有可能对泛型进行具体化,或者JVM是否需要以某种方式进行更改?如果JVM确实需要更改,那么具体需要更改什么?

否-如果字节码不支持具体化的泛型,Scala就不可能作为Java等效字节码运行

当你问“需要更改的是什么?”时,答案是:字节码规范。目前字节码不允许定义变量的参数化类型。已经决定,作为对字节码的修改,以支持具体化的泛型,将


为了解决这个问题,Scala利用其
隐式
机制的强大功能定义了一个
清单
,它可以在任何范围内导入以在运行时发现类型信息。舱单是实验性的,基本上没有文档记录,但它们是真实的。这里是另一个关于

的好资源,只是为了补充oxbow_lakes,这里有一个关于堆栈溢出的问题。

隐式清单是Scala编译器的技巧,它不会使Scala中的泛型具体化。Scala编译器,当它看到一个带有“implicit m:Manifest[a]”参数的函数并且知道调用站点上a的泛型类型时,它会将a的类及其泛型类型参数包装到一个清单中,并使其在函数内部可用。然而,如果它不能找出A的真正类型,那么它就无法创建清单。换句话说,如果内部函数需要,则必须沿着函数调用链传递清单

scala> def typeName[A](a: A)(implicit m: reflect.Manifest[A]) = m.toString
typeName: [A](a: A)(implicit m: scala.reflect.Manifest[A])java.lang.String

scala> typeName(List(1))
res6: java.lang.String = scala.collection.immutable.List[int]

scala> def foo[A](a: A) = typeName(a)
<console>:5: error: could not find implicit value for parameter m:scala.reflect.Manifest[A].
       def foo[A](a: A) = typeName(a)
                                  ^

scala> def foo[A](a: A)(implicit m: reflect.Manifest[A]) = typeName(a)
foo: [A](a: A)(implicit m: scala.reflect.Manifest[A])java.lang.String

scala> foo(Set("hello"))
res8: java.lang.String = scala.collection.immutable.Set[java.lang.String]
scala>def typeName[A](A:A)(隐式m:reflect.Manifest[A])=m.toString
typeName:[A](A:A)(隐式m:scala.reflect.Manifest[A])java.lang.String
scala>typeName(列表(1))
res6:java.lang.String=scala.collection.immutable.List[int]
scala>def foo[A](A:A)=类型名(A)
:5:错误:找不到参数m:scala.reflect.Manifest[A]的隐式值。
def foo[A](A:A)=类型名(A)
^
scala>deffoo[A](A:A)(隐式m:reflect.Manifest[A])=typeName(A)
foo:[A](A:A)(隐式m:scala.reflect.Manifest[A])java.lang.String
scala>foo(Set(“hello”))
res8:java.lang.String=scala.collection.immutable.Set[java.lang.String]
一旦scalac成为编译器,它就有可能用实现具体化泛型所需的任何数据结构来修饰生成的代码

我的意思是scalac可以看到

// definition
class Klass[T] {
  value : T
}

//calls
floats  = Klass[float]
doubles = Klass[double]
。。。并“扩展”到如下内容:

// definition
class Klass_float {
  value : float
}
class Klass_double {
  value : double
}

// calls
floats  = Klass_float
doubles = Klass_double
编辑

要点是:编译器能够创建所有必要的数据结构,这些数据结构证明在运行时提供额外的类型信息是必要的。一旦此类型信息可用,Scala运行时将利用它,并可以执行我们可以想象的所有类型感知操作。JVM是否为具体化的泛型提供字节码并不重要。这项工作不是由JVM完成的,而是由Scala库完成的

如果您已经编写了一个符号调试器(我已经编写了!),那么您知道基本上可以将编译器在编译时拥有的所有信息“转储”到生成的二进制文件中,采用任何数据组织都可以更方便地进一步处理。这与Scala编译器的“转储”所有类型信息的想法完全相同

简而言之,我不明白为什么它不可能,不管JVM是否为具体化的泛型提供本机操作。JVM字节码与具体化的泛型无关。这类事情涉及语言规范、编译器特性和运行时库支持

另一次编辑


IBMX10展示了我所说的能力:它将X10代码编译成Java代码,在Java平台上利用具体化的泛型。正如我前面提到的:这是可以做到的(IBM X10也做到了!),但这种特性涉及语言规范、编译器支持(或编译器插件)以及运行库中的足够支持。更多信息请访问:

补充oxbow_lakes回答:这是不可能的,而且似乎永远不会发生(至少很快)

JVM不支持具体化泛型的(可反驳的)原因似乎是:

  • 性能较低
  • 它破坏了向后兼容性。可以解决复制和修复大量库的问题
  • 它可以使用清单来实现:“解决方案”和最大的障碍
参考资料:

  • :“我更喜欢使用类型擦除的更简单的VM体系结构”

  • 在scala内部构件清单(2013年2月)中:

您可以轻松地对其进行基准测试,并看到性能影响非常大 值得注意的特别是内存消耗增加了很多

我相信我们要走的路是选择物化的方式 开始在Scala中使用清单/类型标签

如果可以,并将其与运行时专门化相结合,您可以实现以下目标 高性能和通用代码。然而,这可能是我们的目标 Scala 2.12或2.13


在你说话的时候添加链接:-)我不知道Scala的人在这么做。这很酷。小更正:清单自2.7.2以来一直是标准库的实验部分。我不知道它们在2.8中是否会更少实验性。IBM X10在编译为Java时提供了具体化的泛型(它也可以编译为C++)。看看这个:这个答案是误导性的——没有基本的JVM限制阻止您实现具体化的泛型。所有具体化的泛型都要求编译器可以根据需要发出类型专门化的类,这在JVM上是完全可能的