以String为例html
Class<? extends String> strCls = "".getClass(); Class<String> strCls2 = String.class; Class strCls3 = Class.forName("java.lang.String"); System.out.println(strCls.equals(strCls2)); // true System.out.println(strCls.equals(strCls3)); // true
对于第一种方式:经过一个String实例的getClass方法来获取,这个函数的签名以下:java
public final native Class<?> getClass();
但文档中对这个函数的解释以下:express
The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();数组
因此上面就要用Class<? extends String>来接收返回值了。函数
对于第三种方式 forName的返回值为 Class<?>,这个等价于Class。例如 List 同 List<?> 是同样的。 测试
三种方式获取到的返回值都是同样的,由于String的字节码对象也就只有一个。ui
http://www.javashuo.com/article/p-cmivtvcj-a.htmlthis
static class DemoClassParent <T> { private Map<X, T> xs; private void show(Map<X, T> data, int y){} } static class DemoClassB extends DemoClassParent<Integer> {} Type type = DemoClassB.class.getGenericSuperclass(); // clazz.getGenericInterfaces() if(type instanceof ParameterizedType){ ParameterizedType pType = (ParameterizedType) type; // 若是父类泛型有多个,则这里会循环屡次 for (Type type2 : pType.getActualTypeArguments()) { if(type2 instanceof Class){ Class target = (Class) type2; System.out.println(target.getName()); } } } // 输出 java.lang.Integer
static class X {} static class DemoClassA { private Map<String, X> xs; private int kkk; private void show(Map<String, X> data, int y){} } static void ayalyse(Type gType){ if(gType instanceof Class){ System.out.println("非泛型类型:" + gType.getTypeName()); return; } if(!(gType instanceof ParameterizedType)){ return; } ParameterizedType pType = (ParameterizedType) gType; System.out.println("泛型参数类型:" + pType.getRawType().getTypeName()); Type[] actualTypeArguments = pType.getActualTypeArguments(); for (Type type2 : actualTypeArguments) { if(type2 instanceof Class){ Class target = (Class) type2; System.out.println(target.getName()); } } } static void test(Class clazz){ System.out.println("---- 反射成员属性"); for(Field field:clazz.getDeclaredFields()){ Type t = field.getGenericType(); ayalyse(t); } System.out.println("---- 反射成员函数"); for(Method method : clazz.getDeclaredMethods()){ // 获取函数参数类型 for (Type type : method.getGenericParameterTypes()) { ayalyse(type); } } } public static void main(String[] args) { test(DemoClassA.class); }
运行结果:spa
---- 反射成员属性
泛型参数类型:java.util.Map
java.lang.String
com.example.demo.DemoApplication$X
非泛型类型:int
---- 反射成员函数
泛型参数类型:java.util.Map
java.lang.String
com.example.demo.DemoApplication$X
非泛型类型:intcode
可见,以上例子的关键在于解析反射出来的type接口子类。Type接口的子类有5个:ParameterizedType,TypeVariable,GenericArrayType,Class,WildcardType。(后续说的T,都是泛型类上的泛型参数T)
表明了包含泛型信息的类型。如List<String>,List<T>,DemoA<String>等
public interface ParameterizedType extends Type { //获取<>中的实际类型 Type[] getActualTypeArguments(); //获取<>前的实际类型 Type getRawType(); //若是当前类型对应的类是内部类,则返回这个内部类对应的外部类的类型,不然返回null Type getOwnerType(); }
表明了不包含泛型信息的类型(不包括基本类型,如int),即定义中没有<>的类,有T,Object等。
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement { // 获取泛型类型的上限,若是没有上限(即 class Person<T>{},这里的类型变量T 没有上限),那么上限为Object Type[] getBounds(); // 获取声明该类型变量的类好比( TypeTest<T> 中的TypeTest ) D getGenericDeclaration(); // 获取类型变量在源码中定义的名称,如T String getName(); AnnotatedType[] getAnnotatedBounds(); }
演示一下前三个方法:
public class TypeTest<T extends String & Comparable<String>> {//继承String,实现接口Comparable<String>,能够用&链接多个接口 public static void main(String[] args) throws NoSuchFieldException, SecurityException, NoSuchMethodException { TypeVariable tv[] = TypeTest.class.getTypeParameters(); Type[] ts = tv[0].getBounds(); for( Type t : ts ){ System.out.println( t ); } } } 输出: class java.lang.String java.lang.Comparable<java.lang.String> public class TypeTest<T> { public static void main(String[] args) throws NoSuchFieldException, SecurityException, NoSuchMethodException { TypeVariable tv[] = TypeTest.class.getTypeParameters(); System.out.println( tv[0].getGenericDeclaration() ); System.out.println( tv[0].getName() ); } } 输出: class testProject.TypeTest T
表明了泛型数组类型。如List<T>[],List<String>[],T[],DemoA<T>[],DemoA<String>[]等。
public interface GenericArrayType extends Type { Type getGenericComponentType(); }
这个函数返回泛型数组中元素的Type类型,即List<String>[] 中的 List<String>(ParameterizedTypeImpl),T[] 中的T(TypeVariableImpl),List<String>[][]中的List<String>[]();
表明了泛型参数。如List,DemoA,String,List[],int[],int.
public final class Class<T> extends Object implements Serializable,GenericDeclaration,Type,AnnotatedElement
getTypeParameters方法:返回当前类的泛型信息
class People<T,V,S>{ } class Chinese extends People<String,Integer,Double>{ } TypeVariable[] tv = People.class.getTypeParameters(); System.out.println( tv.length ); for( TypeVariable t : tv ){ System.out.println( t ); } TypeVariable[] tv1 = Chinese.class.getTypeParameters(); System.out.println( tv1.length ); 输出: 3 T V S 0
getGenericSuperClass:获取父类的泛型信息。
如( class Chinese extendis People<String,Integer,Double>{},返回的是People<String,Integer,Double>,若是没有父类,返回的是Objec的Class实例 )
getGenericInterfaces:获取接口中的泛型信息。
如(class Chinese extends People<String,Integer,Double> implements SpeakChinese<String>,UseChopsticks<Double>{},返回的是SpeakChinese<String>,UseChopsticks<Double>,若是没有实现的接口,返回的Type数组长度为0)。
public interface WildcardType extends Type{ Type[] getLowerBounds(); // 获取下限 Type[] getUpperBounds(); // 获取上限 }
测试代码
List<? extends String> upperBoundsList; List<? super Integer> lowerBoundsList; Field upperBoundsList = TypeTest.class.getDeclaredField("upperBoundsList"); ParameterizedType pt = (ParameterizedType)upperBoundsList.getGenericType(); Type[] types = pt.getActualTypeArguments(); System.out.println( ((WildcardType)types[0]).getUpperBounds()[0] ); // class java.lang.String Field lowerBoundsList = TypeTest.class.getDeclaredField("lowerBoundsList"); ParameterizedType pt1 = (ParameterizedType)lowerBoundsList.getGenericType(); Type[] types1 = pt1.getActualTypeArguments(); System.out.println( ((WildcardType)types1[0]).getLowerBounds()[0] ); //class java.lang.Integer
因为编译期间存在泛型擦除,因此字节码对象不会由于泛型而出现差别。泛型擦除存在限制,并非全部的泛型都会擦除,而是只有函数内建立的局部变量的泛型会被擦除。
List<String> ls = new ArrayList<String>(); System.out.println(ls.getClass().equals(ArrayList.class)); // true
List<String> list = new ArrayList<>(); list.add("string"); // list.add(true); // 编译报错 System.out.println(list); // 使用反射绕过泛型的限制,往限制为String元素的list中添加其余类型的元素 Method mt = list.getClass().getDeclaredMethod("add", Object.class); mt.invoke(list, true); System.out.println(list);
ps:当前类不是泛型类,可是父类是泛型类,这时候父类的泛型必需要被明确的类型指定。除非当前类为泛型类,父类的泛型沿用当前类的泛型。
以hashMap为例,当前为泛型类,并且父类的泛型沿用了当前类的泛型
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
获取泛型信息:
Map<String, Integer> map = new HashMap<String, Integer>(); Type type = map.getClass().getGenericSuperclass(); ParameterizedType parameterizedType = ParameterizedType.class.cast(type); for (Type typeArgument : parameterizedType.getActualTypeArguments()) { System.out.println(typeArgument.getTypeName()); }
输出
K
V
可是若是把
Map<String, Integer> map = new HashMap<String, Integer>();
换成
Map<String, Integer> map = new HashMap<String, Integer>(){};
以上代码就会输出:
java.lang.String
java.lang.Integer
这是由于第一种写法中,父类沿用子类的泛型,而子类的泛型被擦除了,因此获取父类的泛型就获取不到了。第二种中,至关于建立了一个HashMap的匿名内部类对象,父类的泛型信息被保存了下来。
static Map<String, Integer> map = new HashMap<String, Integer>(); public static void main(String[] args) throws Exception { Type type = DemoApplication.class.getDeclaredField("map").getGenericType(); ParameterizedType parameterizedType = ParameterizedType.class.cast(type); for (Type typeArgument : parameterizedType.getActualTypeArguments()) { System.out.println(typeArgument.getTypeName()); } }
运行结果和上一个例子同样。
例子2.2中已经显示出来。