我正在编写一些依赖于某些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一起使用吗?
答案 0 :(得分:2)
好吧,因为我在评论中的黑暗镜头证明是幸运的,同样的答案。
适用于
def foo(numbers: java.util.Set[java.lang.Long])
java.lang.Long
与scala的Long
不同。值得注意的是,Set[java.lang.Long]
可以包含null
,Set[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