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.