最近看Spring 源代碼的時候遇到了一個關于泛型的問題,于是就請教我的老大幫我

解釋了一下,然后又自己看了一點資料,感覺對泛型已經有了一定的理解了,就先

把這些想法記錄下來,供有需要的人參考同時也為了能夠加深理解

如果你在看JDK1.5的源碼的時候就會發(fā)現,java.util.HashMap這個類里面出現了

這種代碼:
public class HashMap<K,V>
    
extends AbstractMap<K,V>
    
implements Map<K,V>, Cloneable, Serializable
{



public HashMap(Map<? extends K, ? extends V> m) {.}
}

里面出現了大量的角號和K,V,T...等不明所以的代碼,其實這就是泛型的應用。

泛型的一些概念:
List<E>  , List< String >   , List
List<E>是參數話類型 parameterized type ,
E是(formal)類型參數 type parameter,
String 實際類型參數 actual type argument,
List是自然類型 raw type

為什么會出現泛型:
原來的JDK中
當我不知道user到底是個什么對象的時候只能這樣寫:
static Object maskNull(Object o){
       return key == null ? NULL_KEY :key;
}

如果我在外面使用的時候:
User u = ...;
User user = (User)map.maskNull(u);
這里用到了向上轉型,把map.maskNull(u)的返回對象強制轉型為了User,強制轉為什么類型完全有程序員控制,所以我在這里這樣寫也是可以的
Department d  =  (Department)map.maskNull(u);
這個錯誤在編譯的時候是不會有任何錯誤提示的,必須到了runtime才能知道返回的類型和Department是不匹配的

但是如果使用了泛型以后我可以寫成這樣
static <T> T maskNull(T key) {
        return key == null ? (T)NULL_KEY : key;
    }

User u = ...;
User user = map.maskNull(u);

當我再寫成Department d = map.maskNull(u);
的時候就會編譯失敗,因為方法要求參數和返回值必須是 T 類型的,當然這里的T只是暫時的一個聲明,類似于去占一個坑,當我需要是User類型的時候,我就用 User去替換掉它,這樣編譯的時候就要求傳進的和返回的必須是一致的類型,所以我們剛才的那種寫法就不行了,這樣編譯器就使用自身的機制保證類型安全type-safe

但是泛型還存在另外一個重要的概念bridge method
先講一下JDK對泛型的支持:上面的講解雖然說泛型很有用,但是泛型在runtime是沒有任何作用的,只是為了編譯期的方便,所以當過了編譯期之后還是要轉換為普通代碼的執(zhí)行方式的,也就是說過了編譯期,帶角號的部分會被抹掉,變成了原始的方式
static Object maskNull(Object o){...}
那么現在看下面的代碼:

class A<T>{
    T setX(T t){...}
}

class B extends A<String>{
    String setX(String s){...}
}

很明顯,當B的方法void String setX(String s)重載了A的方法,但是按照我們剛才講的理論A被編譯成了
class A{
    Object setX(Object t){...}
}
也就是說經過編譯期之后類B的方法就不重載了A的方法,這是不被允許的,所以載編譯的時候同樣有兩外一件事情發(fā)生:JDK會幫你添加一個幫助方法來重載A的方法,于是B就變成了:
class B extends A{
    String setX(String s){...}
    Object setX(Object o){
       return setX((String)o);
    }
}

大家看到多了個重載A類方法的一個方法:
Object setX(Object o){...}
這個方法就是所謂的bredge method
這個工作是在編譯期完成的。所以如果你遍歷A上的方法的時候如果發(fā)現多了方法千萬不要感覺以外

注意這個方法的重載對EL表達式和TPL的運行不存在影響,因為不管用的哪個方法,經過TPL的轉型之后結果都是一樣的