爲何要寫這一系列的博客呢?java
由於在 Android 開發的過程當中, 泛型,反射,註解這些知識進場會用到,幾乎全部的框架至少都會用到上面的一兩種知識,如 Gson 就用到泛型,反射,註解,Retrofit 也用到泛型,反射,註解 。學好這些知識對咱們進階很是重要,尤爲是閱讀開源框架源碼或者本身開發開源框架。程序員
註解使用入門(一)bash
錯誤可分爲兩種:編譯時錯誤與運行時錯誤。編譯時錯誤在編譯時能夠發現並排除,而運行時錯誤具備很大的不肯定性,在程序運行時才能發現,形成的後果多是災難性的。測試
泛型的引入使得一部分錯誤能夠提早到編譯時期發現,極大地加強了代碼的健壯性。可是咱們知道 java 泛型在運行的時候是會進行泛型擦除的,那咱們要怎樣獲得在編譯時期泛型的信息呢?java 爲咱們提供了 Type 接口,使用它,咱們能夠獲得這些信息。ui
不知道什麼是泛型擦除的同窗能夠看一下
類型擦除是指泛型在運行的時候會去除泛型的類型信息。java 中,泛型主要是在編譯層次來實現的,在生成的字節碼即 class 文件是不包括泛型的 類型信息的。 即 List, List ,List 雖然在編譯時候是不一樣的,可是在編譯完成後,在class 文件 中都只會把他們看成 List 來對待。
簡單來講:Type是全部類型的父接口, 如原始類型(raw types 對應 Class)、 參數化類型(parameterized types 對應 ParameterizedType)、 數組類型(array types 對應 GenericArrayType)、 類型變量(type variables 對應 TypeVariable )和基本(原生)類型(primitive types 對應 Class),。
子接口有 ParameterizedType, TypeVariable, GenericArrayType, WildcardType, 實現類有Class。
官方文檔的說明是這樣的
ParameterizedType represents a parameterized type such as Collection
須要注意的是,並不僅是 Collection 纔是 parameterized,任何相似於 ClassName 這樣的類型都是 ParameterizedType ,好比下面的這些都是 parameterizedType.
Map<String, Person> map;
Set<String> set1;
Class<?> clz;
Holder<String> holder;
List<String> list;
static class Holder<V>{
}
複製代碼
而相似於這樣的 ClassName 不是 ParameterizedType.
Set set;
List aList;
複製代碼
Type[] getActualTypeArguments(); 返回 這個 Type 類型的參數的實際類型數組。 如 Map<String,Person> map 這個 ParameterizedType 返回的是 String 類,Person 類的全限定類名的 Type Array。
Type getRawType() 返回的是當前這個 ParameterizedType 的類型。 如 Map<String,Person> map 這個 ParameterizedType 返回的是 Map 類的全限定類名的 Type Array。
Type getOwnerType();
Returns a {@code Type} object representing the type that this type is a member of.
這個比較少用到。返回的是這個 ParameterizedType 所在的類的 Type (注意當前的 ParameterizedType 必須屬於所在類的 member)。解釋起來有點彆扭,仍是直接用代碼說明吧。 好比 Map<String,Person> map 這個 ParameterizedType 的 getOwnerType() 爲 null,而 Map.Entry<String, String>entry 的 getOwnerType() 爲 Map 所屬於的 Type。
說了這麼多,下面咱們一塊兒來看一下例子,加深印象。
public class ParameterizedTypeBean {
// 下面的 field 的 Type 屬於 ParameterizedType
Map<String, Person> map;
Set<String> set1;
Class<?> clz;
Holder<String> holder;
List<String> list;
// Map<String,Person> map 這個 ParameterizedType 的 getOwnerType() 爲 null,
// 而 Map.Entry<String, String> entry 的 getOwnerType() 爲 Map 所屬於的 Type。
Map.Entry<String, String> entry;
// 下面的 field 的 Type 不屬於ParameterizedType
String str;
Integer i;
Set set;
List aList;
static class Holder<V> {
}
}
複製代碼
public class TestHelper {
public static void testParameterizedType() {
Field f = null;
try {
Field[] fields = ParameterizedTypeBean.class.getDeclaredFields();
// 打印出全部的 Field 的 TYpe 是否屬於 ParameterizedType
for (int i = 0; i < fields.length; i++) {
f = fields[i];
PrintUtils.print(f.getName()
+ " getGenericType() instanceof ParameterizedType "
+ (f.getGenericType() instanceof ParameterizedType));
}
getParameterizedTypeMes("map" );
getParameterizedTypeMes("entry" );
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void getParameterizedTypeMes(String fieldName) throws NoSuchFieldException {
Field f;
f = ParameterizedTypeBean.class.getDeclaredField(fieldName);
f.setAccessible(true);
PrintUtils.print(f.getGenericType());
boolean b=f.getGenericType() instanceof ParameterizedType;
PrintUtils.print(b);
if(b){
ParameterizedType pType = (ParameterizedType) f.getGenericType();
PrintUtils.print(pType.getRawType());
for (Type type : pType.getActualTypeArguments()) {
PrintUtils.print(type);
}
PrintUtils.print(pType.getOwnerType()); // null
}
}
}
複製代碼
print:map getGenericType() instanceof ParameterizedType true
print:set1 getGenericType() instanceof ParameterizedType true
print:clz getGenericType() instanceof ParameterizedType true
print:holder getGenericType() instanceof ParameterizedType true
print:list getGenericType() instanceof ParameterizedType true
print:str getGenericType() instanceof ParameterizedType false
print:i getGenericType() instanceof ParameterizedType false
print:set getGenericType() instanceof ParameterizedType false
print:aList getGenericType() instanceof ParameterizedType false
print:entry getGenericType() instanceof ParameterizedType true
print:java.util.Map<java.lang.String, com.xujun.gennericity.Person>
print:true
print:interface java.util.Map
print:class java.lang.String
print:class com.xujun.gennericity.Person
print:null
print:java.util.Map.java.util.Map$Entry<java.lang.String, java.lang.String>
print:true
print:interface java.util.Map$Entry
print:class java.lang.String
print:class java.lang.String
print:interface java.util.Map
好比 public class TypeVariableBean<K extends InputStream & Serializable, V> ,K ,V 都是屬於類型變量。
public class TypeVariableBean<K extends InputStream & Closeable, V> {
// K 的上邊界是 InputStream
K key;
// 沒有指定的話 ,V 的 上邊界 屬於 Object
V value;
// 不屬於 TypeTypeVariable
V[] values;
String str;
List<K> kList;
}
複製代碼
TypeVariableBean bean = new TypeVariableBean<FileInputStream, String>();
fk = TypeVariableBean.class.getDeclaredField("key");
eyType = (TypeVariable) fk.getGenericType();
System.out.println(keyType.getName());System.out.println(keyType.getGenericDeclaration());
複製代碼
執行上述代碼,將能夠看到以下的效果
K
class com.xujun.gennericity.beans.TypeVariableBean
represents an array type whose component type is either a parameterized type or a type variable.
簡單來講就是:範型數組,組成數組的元素中有範型則實現了該接口; 它的組成元素是 ParameterizedType 或 TypeVariable 類型
// 屬於 GenericArrayType
List<String>[] pTypeArray;
// 屬於 GenericArrayType
T[] vTypeArray;
// 不屬於 GenericArrayType
List<String> list;
// 不屬於 GenericArrayType
String[] strings;
// 不屬於 GenericArrayType
Person[] ints;
複製代碼
下面咱們一塊兒來看一下例子
public class GenericArrayTypeBean<T> {
public void test(List<String>[] pTypeArray, T[] vTypeArray,
List<String> list, String[] strings, Person[] ints) {
}
}
複製代碼
public static void testGenericArrayType() {
Method method = GenericArrayTypeBean.class.getDeclaredMethods()[0];
System.out.println(method);
// public void test(List<String>[] pTypeArray, T[]
// vTypeArray,List<String> list, String[] strings, Person[] ints)
Type[] types = method.getGenericParameterTypes(); // 這是 Method 中的方法
for (Type type : types) {
System.out.println(type instanceof GenericArrayType);// 依次輸出true,true,false,false,false
}
}
複製代碼
輸出結果
public void com.xujun.gennericity.beans.GenericArrayTypeBean.test(java.util.List[],java.lang.Object[],java.util.List,java.lang.String[],com.xujun.gennericity.Person[])
true
true
false
false
false
{@code ?}, {@code ? extends Number}, or {@code ? super Integer} 這些類型 都屬於 WildcardType
extends 用來指定上邊界,沒有指定的話上邊界默認是 Object, super 用來指定下邊界,沒有指定的話爲 null。
幾個主要方法介紹
下面一塊兒來看一下例子。
public class WildcardTypeBean {
private List<? extends Number> a; // a沒有下界,
// 沒有指定的話,上邊界默認是 Object ,下邊界是 String
private List<? super String> b;
private List<String> c;
private Class<?> aClass;
}
複製代碼
public static void testWildCardType() {
try {
Field[] fields = WildcardTypeBean.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Type type = field.getGenericType();
String nameString = field.getName();
PrintUtils.print("下面開始打印" + nameString + "是否具備通配符");
if (!(type instanceof ParameterizedType)) {
PrintUtils.print("---------------------------");
continue;
}
ParameterizedType parameterizedType = (ParameterizedType) type;
type = parameterizedType.getActualTypeArguments()[0];
if (!(type instanceof WildcardType)) {
PrintUtils.print("---------------------------");
continue;
}
WildcardType wildcardType = (WildcardType) type;
Type[] lowerTypes = wildcardType.getLowerBounds();
if (lowerTypes != null) {
PrintUtils.print("下邊界");
PrintUtils.printTypeArr(lowerTypes);
}
Type[] upTypes = wildcardType.getUpperBounds();
if (upTypes != null) {
PrintUtils.print("上邊界");
PrintUtils.printTypeArr(upTypes);
}
PrintUtils.print("---------------------------");
}
Field fieldA = WildcardTypeBean.class.getDeclaredField("a");
Field fieldB = WildcardTypeBean.class.getDeclaredField("b");
// 先拿到範型類型
PrintUtils.print(fieldA.getGenericType() instanceof ParameterizedType);
PrintUtils.print(fieldB.getGenericType() instanceof ParameterizedType);
ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
// 再從範型裏拿到通配符類型
PrintUtils.print(pTypeA.getActualTypeArguments()[0] instanceof WildcardType);
PrintUtils.print(pTypeB.getActualTypeArguments()[0] instanceof WildcardType);
WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
// 方法測試
System.out.println(wTypeA.getUpperBounds()[0]);
System.out.println(wTypeB.getLowerBounds()[0]);
// 看看通配符類型究竟是什麼, 打印結果爲: ? extends java.lang.Number
System.out.println(wTypeA);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
複製代碼
Type及其子接口的來歷
沒有泛型的時候,只有原始類型。此時,全部的原始類型都經過字節碼文件類Class類進行抽象。Class類的一個具體對象就表明一個指定的原始類型。
泛型出現以後,擴充了數據類型。從只有原始類型擴充了參數化類型、類型變量類型、限定符類型 、泛型數組類型。
咱們知道在 jdk 1.5 之前的時候,是沒有 泛型的。在 jdk 1.5 的時候,才引入了泛型。若是真的在動態運行的時候加入泛型,涉及到 JVM 命令的修改,這無疑是很是致命的。所以折中採起了這樣的策略,在編譯的時候進行檢查,在運行的時候進行擦除,也是咱們說的泛型擦除。 同時這也說明一點,在設計框架的時候,框架的健壯性和靈活性很是重要。
咱們知道如今的框架都會使用泛型,掌握 Type 有利於咱們讀懂它們的源碼,或者本身動手打造框架。如 Android 的經常使用開源框架 Gson ,Retrofit等。
最近更新博客的頻率有點低,主要是由於惰性吧。天天實習完之後,有點累,就不太想寫博客了。我如今也不知道我能堅持到何時,順其天然吧。PS,真的愈來愈佩服那些堅持寫博客的人,大家是最棒的。
掃一掃,歡迎關注個人微信公衆號 stormjun94(徐公碼字), 目前是一名程序員,不只分享 Android開發相關知識,同時還分享技術人成長曆程,包括我的總結,職場經驗,面試經驗等,但願能讓你少走一點彎路。