How do I get the type of a generic in a collection object?

Posted by steveangelis on Wed, 19 Jan 2022 01:23:38 +0100

1. The concept of generics

Generic concept

Generic type: parameterized type, that is, the type of data to be operated is uncertain at the beginning. Only when it is used can it be determined. Specify the data type to be operated as a parameter, and pass in a specific type when it is used to realize code templating.

2. Problems encountered in getting collection generics

1) When learning JDBC design BaseDao < T >, the class encountered a case where it is necessary to assign a generic type to the parent BaseDao < T > when creating a subclass object. The specific code implementation is as follows

public class BaseDao<T> {
    private QueryRunner queryRunner = new QueryRunner();
    // Define a variable to receive generic types
    private Class<T> type;

    // Get the Class object of T and get the type of generic type. The generic type is determined only when it is inherited by subclasses (difficulty!!!)
    public BaseDao() {
        // Gets the type of the subclass
        Class clazz = this.getClass();//this here represents a subclass, because the subclass must first load the parent constructor when creating an object
        // Gets the type of the parent class
        // getGenericSuperclass() is used to get the type of the parent class (generic) of the current class
        // ParameterizedType represents a type with a generic type
        ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
        // Get the specific generic type getActualTypeArguments get the type of the specific generic type
        // This method returns an array of types
        Type[] types = parameterizedType.getActualTypeArguments();
        // Gets the type of the specific generic·
         this.type = (Class<T>) types[0];
    }

2) At this time, we will naturally think about whether the collection can also determine the generic type of the collection's parent object through the new subclass object, and then obtain the generic type through the getGenericSuperclass() method? (take ArrayList set as an example)

public class GetGenericType {
    private static List<String> arr = new ArrayList<>();

    public static void main(String[] args) throws Exception {

        arr.add("zhangsan");
        Type genericSuperclass = arr.getClass().getGenericSuperclass();
        ParameterizedType pty= (ParameterizedType) genericSuperclass;
        System.out.println(pty.getActualTypeArguments()[0]);//E
        
    }

However, the result is the generic definition format "e". Then I go to see that there is no generic attribute type similar to that in the custom BaseDao < T > class in the source code of the direct parent class abstractlist < E > of ArrayList < E >. So arr. Getclass() When getgenericsuperclass () gets the generic type, the output result is the original type, not the generic type passed in when you are real new ArrayList object. This is because the java compiler first checks the generic type in the code, then erases the type, and then compiles it.

2.1. How does Java generics work? What is type erase?

The normal operation of generics depends on the compiler to check the type first, then erase the type, and insert the relevant instructions of cast where the type parameters appear.

The compiler erases all type related information at compile time, so there is no type related information at run time. For example, List < string > is represented by only one List type at run time. Why erase? This is to avoid type inflation.

3. Solutions

At this time, we need to use the dynamic nature of reflection to solve the problem. The solution code is as follows

public class GetGenericType {
    private static List<String> arr = new ArrayList<>();

    public static void main(String[] args) throws Exception {

        Class<GetGenericType> aClass = GetGenericType.class;
        //Get arr attribute through reflection
        Field arr1 = aClass.getDeclaredField("arr");
        //Get generics through properties
        Type genericType = arr1.getGenericType();
        // ParameterizedType represents a type with a generic type
        ParameterizedType pt = (ParameterizedType) genericType;
        // Get the specific generic type getActualTypeArguments get the type of the specific generic type
        // This method returns an array of types
        Type[] actualTypeArguments = pt.getActualTypeArguments();
        System.out.println(genericType);//java.util.List<java.lang.String>
        System.out.println(actualTypeArguments[0]);//class java.lang.String

    }
}

Topics: Java intellij-idea