您说得对,由于擦除的存在,这不是一个容易解决的问题。但我认为它并非无法解决。
基本原则应该是一直跟随类型变量并将其替换为实际参数类型,直到List<E>
。
考虑这两个类:
class B<T> extends AbstractList<T>{}
class A<E> extends B<E>{}
在声明
B
时使用的类型变量名称是
T
,而在从中扩展
A
时使用
E
。因此,我们不能依赖于声明的名称。
- 我们必须遵循子类中的类型变量名称,在父类或接口中用实际值替换变量。
- 这必须从
Field
开始,直到我们碰到List<E>
。(我不确定当List通过多个路径出现在继承关系中时会发生什么。因此,下面没有处理该情况。)
- 当我们最终替换
List
中的E
时,我们可以得出它是否为List<Integer>
。
以下是执行此操作的代码。它有相当多的行数,但适用于您添加的情况(以及我自己添加的一些情况)。实现中可能存在缺陷,但此方法应该有效。
public class ParameterizedTypeHierarchy{
private static class NotListOfIntegerException extends RuntimeException{
private Type elementType;
public NotListOfIntegerException( Type elementType ){
this.elementType = elementType;
}
}
private static class IsAListOfIntegerException extends RuntimeException{}
public static void main( String[] args ) throws NoSuchFieldException{
List<String> fields = Arrays.asList( "f0", "f1", "f2", "c1", "c2", "c3", "c4",
"c5", "c5Neg1", "c6", "c6Neg1", "c7", "c7Neg1", "c7Neg2" );
for( String f : fields ){
Field field = Pojo.class.getField( f );
try{
check( field );
}
catch( IsAListOfIntegerException e ){
System.out.println( f + " (" + field.getType().getSimpleName() + ") is a List<Integer>" );
}
catch( NotListOfIntegerException e ){
if( e.elementType == null ) System.out.println( f + " (" + field.getType().getSimpleName() + ") is NOT a List." );
else System.out.println( f + " (" + field.getType().getSimpleName() + ") is NOT a List<Integer>. It is List<" + e.elementType.getTypeName() + ">." );
}
catch( Exception e ){
e.printStackTrace();
}
}
}
private static boolean check( Field f ){
Type type = f.getGenericType();
if( type instanceof ParameterizedType ){
if( isList( (ParameterizedType) type, null, null ) ) return true;
}
else if( type instanceof Class ){
return fromClass( (Class<?>) type );
}
return false;
}
private static boolean fromClass( Class<?> type ){
Type[] intfs = type.getGenericInterfaces();
if( intfs != null && intfs.length > 0 ){
for( Type intf : intfs ){
if( intf instanceof ParameterizedType && isList( (ParameterizedType) intf, type, null ) ) return true;
}
}
Type st = type.getGenericSuperclass();
if( st == null || Object.class == st ) throw new NotListOfIntegerException( null );
if( st instanceof ParameterizedType ){
if( isList( (ParameterizedType) st, type, null ) ) return true;
}
return false;
}
private static boolean isList( ParameterizedType pt, Class<?> extendingEntity, Type[] types ){
Type raw = pt.getRawType();
if( raw instanceof Class && !List.class.isAssignableFrom( (Class<?>) raw ) ) return false;
Type[] listParamTypes = pt.getActualTypeArguments();
if( raw == List.class ) return listParamTypes[ 0 ] == Integer.class;
Type[] replaced = replaceTypeVars( pt, extendingEntity, types );
Class<?> c = (Class<?>) raw;
return classExtList( c, replaced );
}
private static Type[] replaceTypeVars( ParameterizedType pt, Class<?> impl, Type[] types ){
Map<String, Type> repl = replacements( impl, types );
Type raw = pt.getRawType();
Type[] rawTypeParams = null;
if( raw instanceof Class<?> ){
Class<?> c = (Class<?>) raw;
Type[] actual = pt.getActualTypeArguments();
if( actual == null || actual.length == 0 ) return null;
rawTypeParams = new Type[ actual.length ];
for( int i = 0; i < actual.length; i++ ){
Type tv = actual[ i ];
Type val = null;
if( !( tv instanceof TypeVariable ) ){
rawTypeParams[ i ] = actual[ i ];
}
else{
if( ( val = repl.get( ( (TypeVariable<?>) tv ).getName() ) ) == null )
rawTypeParams[ i ] = tv;
else
rawTypeParams[ i ] = val;
}
}
}
return rawTypeParams;
}
private static Map<String, Type> replacements( Class<?> c, Type[] types ){
if( c == null ) return Collections.emptyMap();
TypeVariable<?>[] tps = c.getTypeParameters();
if( tps == null || tps.length == 0 ) return Collections.emptyMap();
Map<String, Type> map = new HashMap<>();
for( int i = 0; i < tps.length; i++ ){
if( types[ i ] instanceof TypeVariable ) continue;
TypeVariable<?> tv = tps[ i ];
map.put( tv.getName(), types[ i ] );
}
return map;
}
private static boolean classExtList( Class<?> c, Type[] types ){
TypeVariable<?>[] params = c.getTypeParameters();
Type[] intfs = c.getGenericInterfaces();
for( Type intf : intfs ){
if( intf instanceof ParameterizedType ){
ParameterizedType pt = (ParameterizedType) intf;
if( pt.getRawType() == List.class ){
if( pt.getActualTypeArguments()[ 0 ] == Integer.class ) throw new IsAListOfIntegerException();
for( int i = 0; i < params.length; i++ ){
if( params[ i ].getName().equals( pt.getActualTypeArguments()[ 0 ].getTypeName() ) ){
if( types[ i ] == Integer.class ) throw new IsAListOfIntegerException();
throw new NotListOfIntegerException( types[ i ] );
}
}
}
}
}
Type st = c.getGenericSuperclass();
if( st instanceof ParameterizedType ) return isList( (ParameterizedType) st, c, types );
return false;
}
public static class Pojo {
public Object f0;
public List<Integer> f1;
public ArrayList<Integer> f2;
public C1 c1;
public C2<Integer> c2;
public C3<Integer> c3;
public C4<Integer> c4;
public C5<String, Integer> c5;
public C5<String, String> c5Neg1;
public C6<String, Integer> c6;
public C6<String, String> c6Neg1;
public C7<String, Integer> c7;
public C7<String, String> c7Neg1;
public C7<String, ?> c7Neg2;
}
private static interface A<E>{}
private static class B<T> extends AbstractList<T> {
@Override
public T get( int index ){ return null; }
@Override
public int size(){ return 0; }
}
public static class C1 extends B<Integer> {}
public static class C2<T> extends B<T> {}
public static class C3<T> extends B<String> {}
public static class C4<T> extends B<Integer> {}
public static class C5<T1, T2> extends B<T2> {}
public static class C6<T1, T2> implements List<T2> {...}
public static class C7<T1, T2> implements List<T2>, A<T1>{...}
}