List [Int]和List [Integer]的类型擦除的差异 [英] Difference in type erasure of List[Int] and List[Integer]

查看:406
本文介绍了List [Int]和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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆