SoFunction
Updated on 2025-03-09

How to get generic types in generic classes in Java

Java obtains generic types of generic classes

If we write 1 generic class MyBase

public class MyBase<E> {
    public MyBase(){
        
    }

    public Class<?> getEClass() {
		?
    }   
}

I want to write a getEClass method to get the Class object of the generic symbol E.

It is illegal to use () directly, because E is just a symbol and is not instantiated.

1. Reflection scheme

After various Google and various *s, find a way to utilize reflection.

public class MyBase<E> {
    public MyBase(){
        
    }

    public Class<?> getEClass() {
        
        //get the Class object of this own class 
        Class<? extends MyBase> thisClass = ();

        //get the Type Object of supper class
        Type superClassType = ();
        ParameterizedType pt = (ParameterizedType)superClassType;

        //get the Generic Type array
        Type[] genTypeArr = ();
        Type genType = genTypeArr[0];
        if (false == genType instanceof Class){
            return ;
        }

        return (Class<Object>) genType;
    }
}

This method has been tested, but there is a very special limitation.

It is necessary to instantiate anonymous subclasses to be effective.

For example:

   @Test
    void testMyBase() {
        MyBase<String> mybase = new MyBase<String>(){};
        ("E class is {}",());
    }

Note that the braces after new MyBase(){} mean not instantiate MyBase object, but instantiate anonymous subclass of MyBase.

If we write 1 specific subclass MyList

public class MyList<E> extends MyBase<E> {
    public MyList(){

	}
}

Test method:

   @Test
    void testGetEClass() {
        MyList<String> mylist = new MyList<String>();
        ("E class is {}",());
    }

The same is not possible, the reason is

		//get the Type Object of supper class
        Type superClassType = ();
        ParameterizedType pt = (ParameterizedType)superClassType;

Here we can only obtain 1 parent class ParameterizedType (including the Type of the generic parameter list) through the Class object of this class.

JDK itself only provides the getGenericSuperclass() method to obtain the Type object of the parent class

But there is no such thing as getGenericClass() to obtain the Type object of this class...

So once we don't use anonymous subclass

When the following code is executed

MyList<String> mylist = new MyList<String>();
("E class is {}",());

() will get the Type of MyList's parent class MyBase. The problem is that MyBase is not instantiated, so ()[0] will only return E

It's return null

But if we use the anonymous subclass

When the following code is executed

MyList<String> mylist = new MyList<String>(){};
("E class is {}",());

The class of mylist is actually an anonymous subclass MyList$1, its parent class is MyList, and the parent class of anonymous subclass is actually instantiated in the JVM

So ()[0] will return the Class of the generic concrete class String.

2. Reflection Scheme 2

Anonymous subclasses are a bit strange after all.

If you avoid using your anonymous subclass, we have another way

public class MySet extends MyBase<String> {
    public MySet(){
  
    }
}

For example, the MySet class above specifies specific generics when inheriting MyBase, so that it is not a generic class itself.

In this way, generic specific types can be obtained without anonymous subclassing.

Because in this case, once MySet is implemented, because MySet specifies the specific type of inheriting generics, MyBase will also be instantiated in the JVM.

But this solution is not good, and inflexibility is secondly. I have specified specific generic types. Why use getEClass() to obtain the generic specific types? Take one beat several times

  @Test
    void testGetEClass2() {
        MySet myset = new MySet();
        ("Set E class is {}",());
    }

3. Construction method solution

This is also a highly recommended solution by the outside network

public class MyMap<E> {

    private Class<E> eClass;

    public MyMap(Class<E> eClass){
         = eClass;
    }

    public Class<E> getEClass(){
        return ;
    }

}

Let developers pass generic classes externally when initializing, but the risk of hand-shaking mistakes...

Test method:

  @Test
    void testGetEClass3() {
        MyMap<String> myMap= new MyMap<>();
        ("Set E class is {}",());
    }
}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.