Java: how do I get a class literal from a generic type?

后端 未结 8 1312
北荒
北荒 2020-11-22 07:18

Typically, I\'ve seen people use the class literal like this:

Class cls = Foo.class;

But what if the type is generic, e.g. List?

相关标签:
8条回答
  • 2020-11-22 08:22

    You can't due to type erasure.

    Java generics are little more than syntactic sugar for Object casts. To demonstrate:

    List<Integer> list1 = new ArrayList<Integer>();
    List<String> list2 = (List<String>)list1;
    list2.add("foo"); // perfectly legal
    

    The only instance where generic type information is retained at runtime is with Field.getGenericType() if interrogating a class's members via reflection.

    All of this is why Object.getClass() has this signature:

    public final native Class<?> getClass();
    

    The important part being Class<?>.

    To put it another way, from the Java Generics FAQ:

    Why is there no class literal for concrete parameterized types?

    Because parameterized type has no exact runtime type representation.

    A class literal denotes a Class object that represents a given type. For instance, the class literal String.class denotes the Class object that represents the type String and is identical to the Class object that is returned when method getClass is invoked on a String object. A class literal can be used for runtime type checks and for reflection.

    Parameterized types lose their type arguments when they are translated to byte code during compilation in a process called type erasure . As a side effect of type erasure, all instantiations of a generic type share the same runtime representation, namely that of the corresponding raw type . In other words, parameterized types do not have type representation of their own. Consequently, there is no point in forming class literals such as List<String>.class , List<Long>.class and List<?>.class , since no such Class objects exist. Only the raw type List has a Class object that represents its runtime type. It is referred to as List.class.

    0 讨论(0)
  • 2020-11-22 08:22

    Due to the exposed fact that Class literals doesn't have generic type information, I think you should assume that it will be impossible to get rid of all the warnings. In a way, using Class<Something> is the same as using a collection without specifying the generic type. The best I could come out with was:

    private <C extends A<C>> List<C> getList(Class<C> cls) {
        List<C> res = new ArrayList<C>();
        // "snip"... some stuff happening in here, using cls
        return res;
    }
    
    public <C extends A<C>> List<A<C>> getList() {
        return getList(A.class);
    }
    
    0 讨论(0)
提交回复
热议问题