简体   繁体   中英

How to get a class of a generic in a superclass?

How do I get a class of the generic type inside of the super class constructor?

In other words I want a Class<T> instance where T is the generic from my super class. This would work in the code below for the ChildA class where I define the generic class directly in the class itself, but I also need it to work when the child class is a generic class like in the example with GenericChildB .

     /**
     * empty class
     */
    private static class Foo{}
    
    /**
     * non generic class that extends from a generic class
     */
    private static class ChildA extends GenericClass<Foo>{}
    /**
     * generic class that extends from a generic class
     */
    private static class ClassChildB<T> extends GenericClass<T>{}
    
    private abstract static class GenericClass<T> {
        
        @SuppressWarnings("unchecked")
        public GenericClass() {
            Type type = getClass().getGenericSuperclass();
            /**
             * When constructed from ChildA:
             *      type = generics.Main$GenericClass<generics.Main$Foo>
             *      with other worlds the generic type
             * 
             * But when constructed from GenericChildB:
             *      the generic type is just:
             *      type = generics.Main$GenericClass<T>
             *      and it throws an error when trying to cast his to an ParameterizedType
             *      because <T> is not an acctual class.
             * 
             */
            System.out.println(type);
            Class<T> classInstance = (Class<T>) ((ParameterizedType)type).getActualTypeArguments()[0];
            
            //Goal is to get an Class<T> object inside of the constructor of GenericClass
            System.out.println(classInstance);
        }
    }

    public static void main(String[] args) {
        
        //works : 
        GenericClass<Foo> genericClassA = new ChildA();
        
        //does not work:
        GenericClass<Foo> genericClassB = new GenericChildB<Foo>();
        
    }

This happens because of type erasure in Java.

In the first case, you bind the non-generic class ChildA with a concrete implementation of GenericClass ie GenericClass<Foo> at compile-time. So Java is able to use this information.

In the second case, the binding between GenericChildB and Foo only happens at run-time. Java is not able to use this information.

Extend your example this way:

private static class ClassChildC extends ClassChildB<Foo>{}

Because this class is non-generic, the binding happens at compile-time. You will be able to get type information again.

This may or may not be acceptable in your real scenario, but it's pretty much the only way to retain type information with Java type erasure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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