Java泛型Type体系

本文介绍了Java泛型Type体系,包括Method、Field、Constructor、Class与Type的关系,以及Type的子接口ParameterizedType、TypeVariable、WildcardType、GenericArrayType。通过对泛型反射的理解,阐述如何获取带有模板参数的Class、Method、Field的泛型信息,帮助读者深入理解Java泛型。
摘要由CSDN通过智能技术生成

最近看开源代码,看到里面很多Java泛型,并且通过反射去获取泛型信息。如果说要看懂泛型代码,那还是比较容易,但是如果要自己利用泛型写成漂亮巧妙的框架,那必须对泛型有足够的了解。所以这两三天就不在不断地看Java泛型相关的东西。如果说想要明白通过反射去获取泛型信息,那么Type体系是必须要了解的。Java从1.5开始引入泛型,并且也引入了Type体系。首先给出Type的类型树UML图,以便有个整体的认识。

Type接口

这些都在java的reflect包下面,图中带有s的接口返回的是数组,由于画图工具的原因,标记的只有一个类型,没有带[]。可以说是Java泛型反射的基础。这个UML图我只选取了这些类与接口与Type相关的部分。

Method,Field,Constructor,Class与Type

Method,Field,Constructor都是与Type关联的,而Class是Type的子类。从实际泛型中看也是这样的,因为方法,域,构造方法都可以是泛型。

如果从来没有接触过这些,那么一开始接触这些泛型的反射会非常突兀。如果从一些疑问,或者说需求开始思考可能会能够更好地了解这些东西的作用,比如说:我们已经知道能够通过反射(从1.1就开始支持了)获得一个Class里面的方法以及域,但是我们怎么获得一个带有模版参数的Class里面的模版参数呢?比如说下面这个类

class Test<T> {
public <R> void testMethod(R params){
}
}

我们怎么根据Test.class获得T呢?获得T的具体类型?Class实现了接口GenericDeclaration。GenericDeclaration的getTypeParameters()方法就可以获得模版参数。

同样Method能够包含模版参数的地方有四个,模版参数,返回值,函数参数,异常。Method的四个方法分别对应这四个地方(有一个是继承自GenericDeclaration)。Field,Constructor也都是类似。

Method,Field,Constructor,Class都有获得声明的模版参数的方法,这样我们就可以通过反射来获取模版参数类型。

Type的子接口

Type有四个子接口:ParameterizedType,TypeVariable,WildcardType,GenericArrayType。下面分别介绍这四个类型的具体表示的意思。假设我们申明有下面这个类

public class GenericTest<T1,T2 extends Number> {
	private Map<T1 , Integer> map = null;
}

下面我们开始举例说明。

ParameterizedType

ParameterizedType是表示泛型类型,比如说Map<String,Integer>,这就是一个ParameterizedType类型。

ParameterizedType可以获得具体附带的泛型参数(也就是<>中的内容)。getActualTypeArguments就是获得具体的泛型参数。而getRawType是返回原始类型—申明了泛型参数的那个类,方法(也就是<>左边的那个部分,比如ParameterizedType类型Map<String , Integer>, 那么getRawType返回的就是Map.class)。 而getOwnerType则是返回申明了这个类型的类(在内部类中就会返回父类)。下面是一段简单的测试代码。

    	public static void testParameterizedType() throws NoSuchFieldException, SecurityException{
		
		Type mapGenericType = GenericTest.class.getDeclaredField("map").getGenericType();  //ParameterizedType
		if(mapGenericType instanceof ParameterizedType){
			Type basicType = ((ParameterizedType) mapGenericType).getRawType();
			

			System.out.println("basicType equals Map.class is " + (basicType ==Map.class)); //返回True
			
			System.out.println("基本类型为:"+basicType);  //Map
			// 获取泛型类型的泛型参数, 分别为 
			Type[] types = ((ParameterizedType) mapGenericType).getActualTypeArguments();
			for (int i = 0; i < types.length; i++) {
				System.out.println("第"+(i+1)+"个泛型类型是:"+types[i]);
			}
			//返回为 T1, class java.lang.Integer
			
			System.out.println(((ParameterizedType) mapGenericType).getOwnerType());  //null
		}
	}

TypeVariable

这个是泛型参数类型,比如Map<T1,Integer>, 那么T1就是一个泛型参数,而Integer已经是放入了具体的参数了,所以不是TypeVariable。TypeVariable就是申明的泛型参数。像GenericTest的两个泛型参数T1,T2。可以理解为泛型变量,不是我们具体运行时的类型。

TypeVariable可以获得申明了此泛型参数的类型。通过getGenericDeclaration方法。比如GenericTest<T1,T2>, 两个TypeVariable的getGenericDeclaration都会返回GenericTest.class。
同时也可以获得申明的上界,getBounds就可以获得泛型参数的上界列表。下面是一个TypeVariable的例子。

	public static void testTypeVariable() throws NoSuchFieldException, SecurityException{
		
		Type mapGenericType = GenericTest.class.getDeclaredField("map").getGenericType();  //ParameterizedType
		if(mapGenericType instanceof ParameterizedType){
			// 获取泛型类型的泛型参数, 分别为 T1, class java.lang.Integer
			Type[] types = ((ParameterizedType) mapGenericType).getActualTypeArguments();
			for (int i = 0; i < types.length; i++) {
				if( types[i] instanceof TypeVariable){
					// T1 is TypeVariable, and Integer is not.
					System.out.println("the "+(i+1)+"th is TypeVariable");
				}else{
					System.out.println("the "+(i+1)+"th is not TypeVariable");
				}
			}
			
		}
		
		System.out.println("GenericTest TypeVariable");
		
		TypeVariable<Class<GenericTest>>[] typeVariables = GenericTest.class.getTypeParameters();
		
		// console print  T1, T2
		for(TypeVariable tmp : typeVariables){
			System.out.println(""+tmp);
			Type[] bounds = tmp.getBounds(); //return upper bounds
			if(bounds.length > 0){ 
				//T2 has upper bounds which is class java.lang.Number, 
				//T1's upper bounds is Object which is default.
				System.out.println("bounds[0] is: "+bounds[0]);
			}
			
			System.out.println("name is: "+tmp.getName());  //  T1, T2
			System.out.println("GenericDeclaration is equals GenericTest.class: "+ (tmp.getGenericDeclaration()==GenericTest.class)); //GenericTest
		}
	}
	

WildcardType

WildcardType是通配符类型,也就是? extends Number这种。可以获得上下界。具体使用如下

	private Map<? extends Number, ? super Integer> map1 = new HashMap<Integer,Integer>();
	public static void testWildcardType() throws NoSuchFieldException, SecurityException{
		Type mapGenericType = GenericTest.class.getDeclaredField("map1").getGenericType();
		TypeVariable<Class<GenericTest>>[] typeVariables = GenericTest.class.getTypeParameters();
		Type[] types = ((ParameterizedType) mapGenericType).getActualTypeArguments();
		for(Type t : types){
			if(t instanceof WildcardType){
				System.out.println("wildcardType");
				
				if( ((WildcardType) t).getLowerBounds().length > 0 )
				System.out.println((((WildcardType) t).getLowerBounds())[0]); //print java.lang.Integer
				
				if( ((WildcardType) t).getUpperBounds().length > 0 )
					System.out.println((((WildcardType) t).getUpperBounds())[0]); //print java.lang.Number, Object
					
			}
		}
	}

GenericArrayType

这个是数组泛型。比如T1[] tArray。这是变量的声明。比如下面这段代码

	private T1[] tArray = null;
	public static void testGenericArrayType() throws NoSuchFieldException, SecurityException{
		Type tArrayGenericType = GenericTest.class.getDeclaredField("tArray").getGenericType();
		if(tArrayGenericType instanceof GenericArrayType){
			System.out.println("is GenericArrayType");  //
			Type t1 = ((GenericArrayType) tArrayGenericType).getGenericComponentType();
			System.out.println(t1);   // print T1
			if( t1 instanceof TypeVariable){
				System.out.println("t1 is TypeVariable");
				System.out.println(((TypeVariable) t1).getGenericDeclaration());
			}
		}
	}

Class

Class也是实现了Type接口。像前面的代码中得到了java.lang.Integer等,就是返回Class。Class也可以通过getGenericInterfaces()获取实现的接口,通过getGenericSuperclass()获取父类的类型。

总结

整个Type体系主要就是前面介绍的内容了,从Method,Field,Class反射获取Type,然后Type本身又有很多子类型,标明具体的泛型类型。这个是我测试的代码源码

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值