Scala的2.9.1编译器是否丢弃了类型参数信息?

时间:2011-10-10 15:55:47

标签: java generics scala interop

我正在编写一些依赖于某些Scala代码的Java代码(我也写过)。如果使用2.8.0编译Scala但是如果我使用2.9.1则失败,那么试图提供带参数化类型的参数似乎有效。

(简化的)Scala代码看起来大致如下:

package test

import collection.JavaConversions._

class SomeClass {
  def foo(numbers: java.util.Set[Long]) {
    numbers.foreach(println(_))
  }
}

这很好地编译了2.8.0和2.9.1编译器。 Java代码看起来像这样:

package test;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class App {

    public static void main(String[] args) {
        new SomeClass().foo(new HashSet<Long>(Arrays.asList(1L, 2L, 3L)));
    }

}

如果我使用2.8.0编译器编译Scala,那么Java将很快编译(使用Java的1.6.0_26编译器)。但是,如果我使用2.9.1编译Scala,则Java编译器将失败并显示错误:

test\App.java:16: foo(java.util.Set<java.lang.Object>) in test.SomeClass cannot be applied to (java.util.HashSet<java.lang.Long>)
            sc.foo(new HashSet<Long>(Arrays.asList(1L, 2L, 3L)));
              ^
1 error

因此,当Scala 2.8.0在字节码中保留numbers类型为Set<Long>的信息时,2.9.1编译器会发出numbers为{Set<Object>的字节码。{ 1}}。

这是一个错误吗?故意改变的副作用是不幸的(对我而言)? (Scala changelog提到“JavaConversions中的各种修复,以实现更顺畅的互操作”)。如果是这样,有什么办法可以让它与2.9.1一起使用吗?

2 个答案:

答案 0 :(得分:2)

好吧,因为我在评论中的黑暗镜头证明是幸运的,同样的答案。

适用于

def foo(numbers: java.util.Set[java.lang.Long])

java.lang.Long与scala的Long不同。值得注意的是,Set[java.lang.Long]可以包含nullSet[Long]不应该包含{除非类型系统被某种未经检查的强制转换规避)。尽管在这两种情况下都将Set实现为包含引用;在第二种情况下,它们保证不为空。

识别Set[Long]Set[java.lang.Long]会在类型系统中打开漏洞。话虽如此,我不知道改变是否有意。

答案 1 :(得分:2)

简短回答,这很复杂。 Scala类型系统中的Any是一个很好的统一者,但是当你在Java-land时,这是一个完整的小说。

在2.9之前采取的简化视图是错误构思并且破坏了事物。

要了解问题的摇滚和硬地,请阅读邮件列表中Paul Phillips的说法:

http://www.scala-lang.org/node/9157

http://www.scala-lang.org/node/8888

http://www.scala-lang.org/node/8980