Java ArrayList 实现中的类型擦除 [英] type erasure in implementation of ArrayList in Java

查看:26
本文介绍了Java ArrayList 实现中的类型擦除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读有关 Java 泛型 的这篇文章,然后提到 ArrayList 的构造函数看起来有点像这样:

class ArrayList{私有 V[] backingArray;公共数组列表(){backingArray = (V[]) 新对象[DEFAULT_SIZE];}}

我无法理解编译器的类型擦除和类型检查是如何发生的.我得到的一点是类型参数转换为 Object 类型.

我认为它是(用 Object 替换所有 V),但这绝对是错误的.

class ArrayList{私有对象[] backingArray;公共数组列表(){backingArray = (Object[]) new Object[DEFAULT_SIZE];}}

它究竟是如何转换为Object 类型但仍然保留V 的类型安全的?当我有 ArrayListArrayList 时,每个都有两个不同的类吗?如果不是,StringInteger的类型信息存放在哪里?

解决方案

您的类型擦除版本不正确.Object 的类型参数声明不会被擦除,而只是它的用法被擦除.更具体地说:

  • 泛型类型的擦除是其对应的原始类型.因此,对于 ArrayList,它只是 ArrayList.
  • 擦除类型参数是其最左边的界限.
  • 并且所有类型参数都被删除了.类型参数是您在实例化泛型类时使用的参数.因此,ArrayList 将被替换为 ArrayList.

因此,正确的擦除版本是:

class ArrayList {私有对象[] backingArray;公共数组列表(){backingArray = (Object[]) new Object[DEFAULT_SIZE];}}

<块引用>

当我有 ArrayList 和 ArrayList 时,每个都有两个不同的类吗?

不,从来没有这种情况.编译器仅生成泛型类型或方法的一个字节代码表示,并将泛型类型或方法的所有实例映射到唯一表示.

<块引用>

如果不是String和Integer的类型信息存放在哪里?

当编译器执行类型擦除时,它会根据一些预定义的规则删除所有类型信息,偶尔添加所谓的桥接方法,并添加所有必需的类型转换.

所以,例如ArrayListArrayList的以下用法:

ArrayListlist = new ArrayList();列表.添加(1);int value = list.get(0);ArrayListlist2 = new ArrayList();list.add("A");String value2 = list.get(0);

会转换成这样:

ArrayList list = new ArrayList();列表.添加(1);int value = (Integer) list.get(0);ArrayList list2 = new ArrayList();list.add("A");String value2 = (String) list.get(0);

进一步阅读:

I was reading this article on Java Generics and there it is mentioned that the constructor for an ArrayList looks somewhat like this:

class ArrayList<V> {
  private V[] backingArray;
  public ArrayList() {
    backingArray = (V[]) new Object[DEFAULT_SIZE]; 
  }
}

I was not able to understand how type erasure and type checking by the compiler happens as explained there. One point I got was that the type parameter is transformed to Object type.

I would imagine it as (replacing all V with Object), but this definitely wrong.

class ArrayList<Object> {
      private Object[] backingArray;
      public ArrayList() {
        backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
      }
}

How exactly is it transformed to Object type but still retaining the type safety for V? when I have ArrayList<String> and ArrayList<Integer> are there two different classes for each? If not, where is the type information of String and Integer is stored?

解决方案

Your type erased version is not correct. The type parameter declaration is not erased to Object but only it's usage is erased. More specifically:

  • Erasure of a generic type is its corresponding raw type. So, for ArrayList<V>, it would be just ArrayList.
  • Erasure of a type parameter is its left-most bound.
  • And all the type arguments are just removed. The type arguments are the one you use while instantiating the generic class. So, ArrayList<Integer> will be replaced with ArrayList.

So, the correct erased version would be:

class ArrayList {
    private Object[] backingArray;
    public ArrayList() {
      backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
    }
}

when I have ArrayList and ArrayList are there two different classes for each?

No, this is never the case. The compiler generates only one byte code representation of a generic type or method and maps all the instantiations of the generic type or method to the unique representation.

if not where the type information of String and Integer is stored?

When the compiler performs type-erasure, it removes all the type information, based on some pre-defined rules, occasionally adding what is called as bridge method, and adds all the necessary type casting required.

So, for example, the following usage of ArrayList<Integer> and ArrayList<String>:

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
int value = list.get(0);

ArrayList<String> list2 = new ArrayList<String>();
list.add("A");
String value2 = list.get(0);

will be converted to somewhat like this:

ArrayList list = new ArrayList();
list.add(1);
int value = (Integer) list.get(0);

ArrayList list2 = new ArrayList();
list.add("A");
String value2 = (String) list.get(0);

Further Reading:

这篇关于Java ArrayList 实现中的类型擦除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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