在Java中实现ArrayList时键入擦除

bra*_*orm 12 java generics constructor arraylist object

我正在阅读关于Java Generics的这篇文章,并且在那里提到了一个ArrayList看起来像这样的构造函数:

class ArrayList<V> {
  private V[] backingArray;
  public ArrayList() {
    backingArray = (V[]) new Object[DEFAULT_SIZE]; 
  }
}
Run Code Online (Sandbox Code Playgroud)

我无法理解编译器的类型擦除和类型检查是如何解释的那样.我得到的一点是type参数转换为Objecttype.

我将它想象成(更换所有VObject),但是这肯定是不对的.

class ArrayList<Object> {
      private Object[] backingArray;
      public ArrayList() {
        backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
      }
}
Run Code Online (Sandbox Code Playgroud)

它究竟是如何转变为Object类型但仍保留类型安全性的V?当我有ArrayList<String>ArrayList<Integer>是否有两种不同类型的每一个?如果没有,在哪里类型的信息StringInteger存储?

Roh*_*ain 8

您的类型擦除版本不正确.类型参数声明不会被删除,Object只会删除它的用法.进一步来说:

  • 擦除泛型类型是其对应的原始类型.所以,因为ArrayList<V>,它只是ArrayList.
  • 类型参数的擦除是其最左边界限.
  • 并且所有类型参数都被删除了.类型参数是在实例化泛型类时使用的参数.所以,ArrayList<Integer>将被取代ArrayList.

所以,正确的擦除版本将是:

class ArrayList {
    private Object[] backingArray;
    public ArrayList() {
      backingArray = (Object[]) new Object[DEFAULT_SIZE]; 
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

如果没有存储String和Integer的类型信息的位置?

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

因此,例如,以下用法ArrayList<Integer>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);
Run Code Online (Sandbox Code Playgroud)

将转换为有点像这样:

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);
Run Code Online (Sandbox Code Playgroud)

进一步阅读:

  • @brainstorm这就是重点.`String []`根本没有创建.泛型类本身内部没有类型参数的信息.后备数组仍然是`Object []`.列表仍然会返回一个`Object`引用.这就是为什么需要将它"list.get(0)"转换为`String`. (2认同)