type erasure in implementation of ArrayList in Java

前端 未结 3 1357
自闭症患者
自闭症患者 2021-02-08 00:16

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

class ArrayLis         


        
相关标签:
3条回答
  • 2021-02-08 00:35

    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

    0 讨论(0)
  • 2021-02-08 00:42

    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 Generics FAQs - What is Type Erasure?
    • Why does compiler adds cast while translating generics?
    0 讨论(0)
  • 2021-02-08 01:01

    Your second example is incorrect. Type erasure does not imply globally casting everything to Object. As you surmised, this hardly makes any sense. Instead, what type erasure does is (literally) the following (borrowed from 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. Type erasure "erases" the types of generics and casts all objects therein to 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.

    0 讨论(0)
提交回复
热议问题