以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中已經顯示出來。