List [Int]和List [Integer]的类型擦除的差异 [英] Difference in type erasure of List[Int] and List[Integer]
问题描述
为什么在List[java.lang.Integer]
中的Integer
出现时List[scala.Int]
类型将擦除到List[Object]
要保存?例如,javap
表示
Why does List[scala.Int]
type erase to List[Object]
whilst Integer
in List[java.lang.Integer]
seems
to be preserved? For example, javap
for
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
的位置. docs 状态
where we see Integer
was preserved in second case. The docs state
将通用类型中的所有类型参数替换为其边界,如果类型参数无界,则将其替换为
Object
.
这可能是由于"bounds"子句引起的吗?如果是这样,该界限在哪里指定?
Is this perhaps due to the "bounds" clause? If so, where is this bound specified?
推荐答案
我不是Scala开发人员,请带着一粒盐.擦除 相同:
I am not a scala developer, take this with a grain of salt. The erasure is the same:
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
参数;这就是在字节代码级别的呼叫站点上引用的内容.
look at the descriptor
parameter; that is what gets referenced at call sites at the byte code level.
当您简单地执行javap
时,通过查看Signature
参数(进一步阅读),它会欺骗"一点,以便向您显示这个小小的冒犯性谎言.
When you simply do javap
, it "cheats" a little bit by looking at the Signature
parameter (read further) so that it shows you this little inoffensive lie.
现在考虑一下.让我们采用此方法并将其放在类A
中:
Now think about it. Let's take this method and place it in class A
:
static List<Integer> test() {
return null; // or whatever that is not the point
}
我们编译它,将.class
文件共享给其他人.有人以这种形式使用它:(实际上没有A
的源代码).
we compile it, share the .class
file to someone else. That someone else uses it in this form: (without actually having source code for A
).
public void testMe() {
Integer x = A.test().get(0);
}
如果您查看字节码,将会看到:
if you look at the byte-code, you will see:
5: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
10: checkcast #4 // class java/lang/Integer
必须立即提出一个问题:如果删除了泛型,它如何知道Integer
(通过checkcast
)?答案是可选的Signature
,它是在编译A
时或在您遇到的情况下生成的:
There is an immediate question that has to arise: how does it know about Integer
(via that checkcast
) if generics are erased? The answer is the optional Signature
that is generated when A
is compiled, or in your cases:
()Lscala/collection/immutable/List<Ljava/lang/Object;>; //fooInt
()Lscala/collection/immutable/List<Ljava/lang/Integer;>; // fooInteger
此Signature
信息是编译器用来通过运行时检查在 callsites 上强制类型安全的信息;如果该字段不存在-那将是不可能的.
This Signature
information is what is used by the compiler to enforce type safety at callsites, via runtime checks; if this field would not be present - that would have been impossible.
现在Signature
为什么 生成Object
(因此,呼叫者的零类型安全性)是重复地址.我已经尝试阅读该问题,但阅读起来并不容易,我会选择我信任你".
Now to why the Signature
of scalac
generates Object
(thus zero type safety for callers) is something that the duplicate addresses. I've tried to read the issue and it's not an easy read- I'll just go with "I trust you".
更多说明:Signature
在添加泛型时出现在java-5
中.在此之前,所有由descriptor
引用的呼叫站点,将其更改为Signature
都将意味着现有代码将中断.因此从来没有做过.因此,Signature
成为可选的,并以不同的方式使用-用于checkcast
.至少这是我极力假设的:)
A little more explanations: Signature
appeared in java-5
when generics where added. Until then, all call-sites where referenced by descriptor
, changing that to Signature
instead would mean that existing code would break; thus never done. Thus Signature
became optional and used in a different way - for checkcast
. At least this is what I am strongly inclined to assume :)
这篇关于List [Int]和List [Integer]的类型擦除的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!