学习范型的第一课就被警告说,范型信息再编译之后是拿不到的,因为已经被擦除掉了。如果不深入研究,这个观点很容易给人以这样的错觉:只要代码里面用了范型的地方,编译之后,是没法拿到这部分信息的!
关于这点的错误之处,可以参考撒伽的这篇文章。 按他的解释是说:
位于声明一侧的,源码里写了什么到运行时就能看到什么;
位于使用一侧的,源码里写什么到运行时都没了。
这里,最根本的原因,还是因为jdk1.5之后,将范型类、方法、属性的信息,都固化到了编译之后的class文件中(具体的例子可以参考上面提高文章中反编译class文件之后拿到的信息),java本身也就有能力通过反射的API来获取这部分信息了。关于这个使用方法的实例,《Generic Data Access Objects》提供了演示。
不过,光看上面的文章,在自己操作处理范型信息时,java提供的API还是有点问题的。
这里,我们必须先搞清楚下面提到的几个概念:
- type parameters:范型类或者范型接口声明里面的“范型参数”,比如:List<E>这个范型接口中,有一个type parameter,就是E。
- parameterized types: “泛化类型”是指范型类或这范型接口本身,比如:List<String>就是一个具体的parameterized type。
- actual type parameter:范型使用中,实际使用的真实类型。比如:List<String>中,String就是上面提到的E的actual type parameter。
- raw type:踢掉“范型参数”之后,剩下的“裸类型”。比如:List<E>中,List就是List<E>的raw type。
了解了上面的几个基本概念之后,我们分别来看类(或者接口)、方法、属性对应的范型信息获取的API。
一、类(或者接口):参考下面是Class中getTypeParameters方法的实现。
public TypeVariable<Class<T>>[] getTypeParameters() {
if (getGenericSignature() != null)
return (TypeVariable<Class<T>>[])getGenericInfo().getTypeParameters();
else
return (TypeVariable<Class<T>>[])new TypeVariable[0];
}
根据上面提到的概念,Class中这个方法本身的语义不难理解。
这里,返回了一个TypeVariable的数组。关于,TypeVariable接口,只有3个方法:String getName()、D getGenericDeclaration()、Type[] getBounds()。关于这三个方法的使用,具体来看一下下面的例子:
public class GenericT<T,E extends GenericT.B & Serializable> {
private T innerT;
private Map<String,T> nameMap;
//just for demo
public static class A{
}
//just for demo
public static class B extends A{
}
}
public class Main {
public static void main(String[] args) {
showGenericTypeInfo();
}
public static void showGenericTypeInfo(){
TypeVariable<Class<GenericT>>[] typeVariable = GenericT.class.getTypeParameters();
for (TypeVariable<Class<GenericT>> classTypeVariable : typeVariable) {
System.out.println("TypeVariable.getName() : " + classTypeVariable.getName());
System.out.println("TypeVariable.getClass() : " + classTypeVariable.getClass());
StringBuilder sb = new StringBuilder( );
for(Type type : classTypeVariable.getBounds()){
sb.append( ((Class)type).getCanonicalName() ).append( "," );
}
System.out.println("TypeVariable.getBounds() : " + sb.substring(0,sb.length()-1));
System.out.println("TypeVariable.getGenericDeclaration() : " + classTypeVariable.getGenericDeclaration());
}
}
}
这里,为了演示TypeVariable.getBounds()方法,故意把GenericT的第二个type parameter继承了两个type(一个是他的内部类,一个是Serializable接口)。
运行上面的Main.main(),可以得到如下输出:
TypeVariable.getName() : T
TypeVariable.getClass() : class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
TypeVariable.getBounds() : java.lang.Object
TypeVariable.getGenericDeclaration() : class com.sky.www.generic.GenericT
TypeVariable.getName() : E
TypeVariable.getClass() : class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
TypeVariable.getBounds() : com.sky.www.generic.GenericT.B,java.io.Serializable
TypeVariable.getGenericDeclaration() : class com.sky.www.generic.GenericT
二、方法:(参考Method中提供的3个public的跟这个相关的方法)
public Type[] getGenericParameterTypes() {
if (getGenericSignature() != null)
return getGenericInfo().getParameterTypes();
else
return getParameterTypes();
}
public Type getGenericReturnType() {
if (getGenericSignature() != null) {
return getGenericInfo().getReturnType();
} else { return getReturnType();}
}
public Type[] getGenericExceptionTypes() {
Type[] result;
if (getGenericSignature() != null &&
((result = getGenericInfo().getExceptionTypes()).length > 0))
return result;
else
return getExceptionTypes();
}
这3个方法,分别对应获取方法的参数,返回值,异常的范型信息。注意,3个方法的返回值都是一个最上层的Type接口,实际使用时,就可能需要使用者自己去强转一下具体的子接口了。毕竟,Type只是个最高层抽象的类型接口,里面没有任何可以使用的方法,比较常用的子接口至少包括如下几个:
- TypeVariable (java.lang.reflect):上面类的范型信息中提到过。
- ParameterizedType (java.lang.reflect) :参考上面的概念,比如List<String>
- WildcardType (java.lang.reflect):使用范型通配符?类型,比如List<? extends String>
- GenericArrayType (java.lang.reflect) : 字面解释就是“范型数组类型”,主要代表的抽象实体是范型相关的数组。
上面四个最常用的子Type,前三个比较好理解,第四个GenericArrayType说起来有点拗口。(当然Type除了这四个子接口外,在常用的一个实现类就是Class本身了,这个不要忘记,下面的演示中也有示例)来看个下面的具体的例子,这个例子主要是以getGenericReturnType为基础展示的,其他两个完全类似:
public class GenericArrayTypeTest<T> {
// component type is a type variable
public T[] typeParameterDemo(){
return null;
}
// component type is a parameteriazed type
public List<String>[] listArrayDemo(){
return null;
}
// component type is a int.class
public int[] listInt(){
return null;
}
}
public class Main {
public static void main(String[] args) {
showGenericArrayType();
}
public static void showGenericArrayType(){
for(Method method :GenericArrayTypeTest.class.getDeclaredMethods()){
System.out.println("############################################");
System.out.println("Method name : "+method.getName());
Type type = method.getGenericReturnType();
if(type instanceof GenericArrayType){
Type componentType = ((GenericArrayType)type).getGenericComponentType();
System.out.println("GenericArrayType's componentType is : "+componentType);
if(componentType instanceof TypeVariable){
System.out.println(componentType+" is a TypeVariable!");
TypeVariable typeVariable = (TypeVariable)componentType;
System.out.println("TypeVariable.getGenericDeclaration() is : "+typeVariable.getGenericDeclaration());
}else if(componentType instanceof ParameterizedType){
System.out.println(componentType+" is a ParameterizedType!");
ParameterizedType parameterizedType = (ParameterizedType)componentType;
System.out.println("It's raw type is : "+parameterizedType.getRawType());
System.out.println("It's owner type is : "+parameterizedType.getOwnerType());
for(Type type1 : parameterizedType.getActualTypeArguments()){
System.out.println("Actual Type is : "+type1);
}
}
}else if(type instanceof Class){
System.out.println("GenericeReturnType is a class : "+type);
Class cl = (Class)type;
System.out.println("It's name is : " + cl.getCanonicalName());
if(cl.isArray()) {
System.out.println("It is a array!");
Class<?> componentType = cl.getComponentType();
System.out.println("The component type of this array is : "+componentType);
}
}
System.out.println("############################################");
}
}
}
上面一段程序的输出如下:
############################################
Method name : typeParameterDemo
GenericArrayType's componentType is : T
T is a TypeVariable!
TypeVariable.getGenericDeclaration() is : class com.sky.www.generic.GenericArrayTypeTest
############################################
############################################
Method name : listArrayDemo
GenericArrayType's componentType is : java.util.List<java.lang.String>
java.util.List<java.lang.String> is a ParameterizedType!
It's raw type is : interface java.util.List
It's owner type is : null
Actual Type is : class java.lang.String
############################################
############################################
Method name : listInt
GenericeReturnType is a class : class [I
It's name is : int[]
It is a array!
The component type of this array is : int
############################################
三、属性(Field里面只提供了一个public出来的方法,用于获得域属性的范型信息)
public Type getGenericType() {
if (getGenericSignature() != null)
return getGenericInfo().getGenericType();
else
return getType();
}
关于这个API的使用,这里就不举例了,因为获得还是最上层的Type信息,所以具体使用时,还是跟上面Method的演示的差不错,通常涉及到转换成具体的子Type接口才能获得更为具体的信息。具体操作层面上,就是根据情况转换成上面的四个子接口之一或者Class来操作了。
分享到:
相关推荐
Java 范型Java 范型
JAVA范型指南:讲述范型,范型通配符,范型方法,范型与久代码(无范型)的融合,范型的擦除与翻译等...
Java 范型攻略篇
java1.5范型编程指南.docjava1.5范型编程指南.docjava1.5范型编程指南.docjava1.5范型编程指南.docjava1.5范型编程指南.doc
java范型[参考].pdf
java范型[参照].pdf
java范型学习.............
Java范型机制 Java范型机制 Java范型机制 Java范型机制Java范型机制 Java范型机制
java 泛型类的类型识别示例 java 泛型类的类型识别示例 java 泛型类的类型识别示例
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...
范型参考 (1).java
范型参考 (2).java
本例子说明演示了Java范型使用的动机、范型类的使用、范型方法的使用,以及范型的缺陷:类型擦除(type erasure).因为,现在Java的反射机制不能确定集合中的对象类型! 在实际应用中,如果能够灵活应用范型和反射...
Java 实现泛型List的源码,基本实现了List接口的全部所有方法。欢迎大家发表自己的观点和建议。
Java程序设计范型和枚举PPT教案学习.pptx
消息传递范型与C/S范型双范型的主数据管理机制,陈晓云,邢乔金,本文针对主数据管理(MDM)存在的问题提出了一种基于消息传递机制范型与C/S范型双范型的主数据管理机制,当各个分系统的数据有所变化�
C++多范型设计,ISBN:9787508318240,作者:(美)James O.Coplien著;鄢爱兰,周辉等译;鄢爱兰译
p2p
暂时仅仅设计了以下几个功能点: 1.点对点单人聊天; 2.多人在线同时聊天; 3.用户可以自由加入和退出系统; 4.具备用户在线状态监听;
范型程序设计与 STL.pdf,大小约 300K。