Are generics removed by the compiler at compile time

后端 未结 4 734
陌清茗
陌清茗 2020-12-17 21:19

In this tutorial on reflection it states:

[...] because generics are implemented via type erasure which removes all information regarding generic typ

相关标签:
4条回答
  • 2020-12-17 21:29

    In java, Generics is just a place holder. Java Run Time doesn't have any clue about the generics. It's all a compile time trick.

    Setting up generics is exactly similar to the scenario, when you declare a field attribute in a class as

    • Object (When you just declare type as T)
    • MyObject (When you declare type as T extends MyObject).

    After compilation, all would be wired according to the types. That's what is known as Type Erasure.

    0 讨论(0)
  • 2020-12-17 21:44

    The statement that you quoted is correct: the compiler uses the generic type information internally during the process of compilation, generating type-related errors as it processes the sources. Then, once the validation is done, the compiler generates type-erased byte code, with all references to generic types replaced with their respective type erasure.

    This fact becomes evident when you look at the types through reflection: all interfaces, classes, and functions become non-generic, with all types tied to generic type parameters replaced with a non-generic type based on the generic type constraints specified in the source code. Although reflection API does have provisions for accessing some of the information related to generics* at runtime, the virtual machine is unable to check the exact generic type for compatibility when you access your classes through reflection.

    For example, if you make a class member of type List<String> and try setting a List<Integer> into it, the compiler is going to complain. If you try to do the same through reflection, however, the compiler is not going to find out, and the code will fail at run-time in the same way that it would without generics:

    class Test {
        private List<String> myList;
        public void setList(List<String> list) {
            myList = list;
        }
        public void showLengths() {
            for (String s : myList) {
                 System.out.println(s.length());
            }
        }
    }
    
    ...
    
    List<Integer> doesNotWork = new ArrayList<Integer>();
    doesNotWork.add(1);
    doesNotWork.add(2);
    doesNotWork.add(3);
    Test tst = new Test();
    tst.setList(doesNotWork); // <<== Will not compile
    Method setList = Test.class.getMethod("setList", List.class);
    setList.invoke(tst, doesNotWork); // <<== This will work;
    tst.showLengths(); // <<== However, this will produce a class cast exception
    

    Demo on ideone.


    * See this answer for details on getting information related to generic types at runtime.

    0 讨论(0)
  • 2020-12-17 21:46

    It means, when it is being converted into bytecode. For checking whether correct types are used or not, generics are used. But at the time of bytecode generation, information is removed

    0 讨论(0)
  • 2020-12-17 21:47

    Some generics stay in the compiled class -- specifically including method signatures and class definitions, for example. At runtime, no objects keep their full generic type, but even at runtime you can look up the generic definition of a class or a method.

    For example, if you have

    class Foo {
      List<String> getList() { ... }
    
      public static void main(String[] args) {
        System.out.println(Foo.class.getMethod("getList").getGenericReturnType());
        // prints "List<String>"
        List<String> list = new Foo().getList();
        // there is no way to get the "String" parameter on list
    }
    
    0 讨论(0)
提交回复
热议问题