为什么在List[scala.Int]
中的List[Object]
中将Integer
键入擦除到List[java.lang.Integer]
要保存?例如,javap
代表
object Foo {
def fooInt: List[scala.Int] = ???
def fooInteger: List[java.lang.Integer] = ???
}
输出
public scala.collection.immutable.List<java.lang.Object> fooInt();
public scala.collection.immutable.List<java.lang.Integer> fooInteger();
在第二种情况下保留了Integer
的位置。文档state
使用边界将通用类型中的所有类型参数替换为边界,如果类型参数不受限制,则用
Object
替换。
这可能是由于“ bounds”子句引起的吗?如果是这样,该界限在哪里指定?
答案 0 :(得分:5)
我不是Scala开发人员,请带上一粒盐。擦除 相同:
public static scala.collection.immutable.List<java.lang.Object> fooInt();
descriptor: ()Lscala/collection/immutable/List;
public static scala.collection.immutable.List<java.lang.Integer> fooInt();
descriptor: ()Lscala/collection/immutable/List;
查看descriptor
参数;这就是在字节代码级别的呼叫站点上引用的内容。
当您简单地执行javap
时,它会通过查看Signature
参数(进一步阅读)而变得“虚假”,以便向您显示这个小小的冒犯性谎言。
现在考虑一下。让我们采用此方法并将其放在类A
中:
static List<Integer> test() {
return null; // or whatever that is not the point
}
我们进行编译,将.class
文件共享给其他人。有人以这种形式使用它:(实际上没有A
的源代码)。
public void testMe() {
Integer x = A.test().get(0);
}
如果您查看字节码,将会看到:
5: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
10: checkcast #4 // class java/lang/Integer
必须立即提出一个问题:如果删除了泛型,它如何知道Integer
(通过checkcast
)?答案是在编译Signature
时或在您的情况下生成的可选A
。
()Lscala/collection/immutable/List<Ljava/lang/Object;>; //fooInt
()Lscala/collection/immutable/List<Ljava/lang/Integer;>; // fooInteger
此Signature
信息是编译器用来通过运行时检查在呼叫站点强制执行类型安全的信息;如果该字段不存在-那将是不可能的。
现在,{em}的Signature
的{{1}}会生成scalac
(因此,呼叫者的零类型安全)是重复地址。我已尝试阅读该问题,但阅读起来并不容易-我会选择“我信任您”。
更多解释:Object
出现在Signature
中,当时添加了泛型。在此之前,java-5
引用的所有呼叫站点将其更改为descriptor
意味着现有代码将中断;因此从来没有做过。因此Signature
成为可选的,并以不同的方式使用-用于Signature
。至少这是我强烈想要的:)