简体   繁体   English

在Java中实现ArrayList时键入擦除

[英]type erasure in implementation of ArrayList in Java

I was reading this article on Java Generics and there it is mentioned that the constructor for an ArrayList looks somewhat like this: 我正在阅读关于Java Generics的这篇文章,并且在那里提到了ArrayList的构造函数看起来像这样:

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. 我得到的一点是type参数被转换为Object类型。

I would imagine it as (replacing all V with Object ), but this definitely wrong. 我会想象它(用Object替换所有V ),但这绝对是错误的。

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 ? 它究竟是如何转换为Object类型但仍保留V的类型安全性? when I have ArrayList<String> and ArrayList<Integer> are there two different classes for each? 当我有ArrayList<String>ArrayList<Integer> ,每个都有两个不同的类? If not, where is the type information of String and Integer is stored? 如果不存在,那么存储StringInteger的类型信息在哪里?

Your type erased version is not correct. 您的类型擦除版本不正确。 The type parameter declaration is not erased to Object but only it's usage is erased. 类型参数声明不会被删除到Object但只会删除它的用法。 More specifically: 进一步来说:

  • Erasure of a generic type is its corresponding raw type. 擦除泛型类型是其对应的原始类型。 So, for ArrayList<V> , it would be just ArrayList . 因此,对于ArrayList<V> ,它只是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 . 因此, ArrayList<Integer>将替换为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? 当我有ArrayList和ArrayList时,每个都有两个不同的类?

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? 如果没有存储String和Integer的类型信息的位置?

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>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: 进一步阅读:

Your second example is incorrect. 你的第二个例子不正确。 Type erasure does not imply globally casting everything to Object . 类型擦除并不意味着全局将所有内容都转换为Object As you surmised, this hardly makes any sense. 正如你猜测的那样,这几乎没有任何意义。 Instead, what type erasure does is (literally) the following (borrowed from Jon Skeet ): 相反,什么类型的擦除做(字面上)以下(借用Jon Skeet ):

List<String> list = new ArrayList<String>();
list.add("Hi");
String x = list.get(0);

This block of code is translated to: 这段代码被翻译成:

List list = new ArrayList();
list.add("Hi");
String x = (String) list.get(0);

Notice the cast to String , not merely a vanilla Object . 注意转换为String ,而不仅仅是一个vanilla Object Type erasure "erases" the types of generics and casts all objects therein to T . 类型擦除“擦除”泛型的类型并将其中的所有对象强制转换为T This is a clever way to add some compile-time user-friendliness without incurring a runtime cost. 这是一种添加一些编译时用户友好性而不会产生运行时成本的聪明方法。 However, as the article claims, this is not without compromises. 但是,正如文章所声称的那样,这并非没有妥协。

Consider the following example: 请考虑以下示例:

ArrayList<Integer> li = new ArrayList<Integer>();
ArrayList<Float> lf = new ArrayList<Float>();

It may not seem intuitive (or correct), but li.getClass() == lf.getClass() will evaluate to true. 它可能看起来不直观(或正确),但li.getClass() == lf.getClass()将评估为true。

Good Question.The type checking is done first.If everything compiles(that is,after it has provided compile type safety) does type erasure occur. 好问题。首先进行类型检查。如果所有内容都编译(即,在提供编译类型安全性之后),则会发生类型擦除。

Again,lot of things happen as part of type erasure which includes:- 同样,很多事情都是类型擦除的一部分,其中包括: -

1)Adding casts 
2) creating bridge methods

But type checking is done first,everything happens later 但是首先进行类型检查,一切都在以后进行

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM