JAVA泛型筆記

泛型是JDK 1.5的一項新特性,它的本質是參數化類型(Parameterized Type),即所操做的數據類型在定義時被指定爲一個參數。當咱們使用的時候給這個參數指定不一樣的對象類型,就能夠處理不一樣的對象。這種參數類型能夠用在類、接口和方法的建立中,分別稱爲泛型類、泛型接口和泛型方法。java

1、泛型實現方式

泛型聲明方式:<佔位符>
佔位符有兩大類:安全

  1. 普通佔位符,E, T, K, V通常是單字母大寫,表示接收特定的類型。
  2. 通用佔位符,也叫通配符,佔位符中包含「?」問號,表示接任意數據類型或者指定範圍數據類型。

泛型類

泛型類和普通類的區別就是類定義時,在類名後加上泛型聲明。泛型類的內部成員、方法就可使用聲明的參數類型。泛型類最多見的用途就是做爲容納不一樣數據類型的容器類,好比Java集合容器類。ide

class GenericClass<T>{
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

泛型接口

和泛型類同樣,泛型接口在接口名後添加泛型聲明,接口方法就能夠直接使用聲明的參數類型。
實現類在實現泛型接口時須要指明具體的參數類型,否則默認類型是 Object,這就失去了泛型接口的意義。this

interface genericInterface<K, V> {
    K getKey();
    V getValue();
}

未指明類型的實現類,默認是 Object 類型:code

class GenericClass implements genericInterface{
    @Override
    public Object getKey() {
        return null;
    }

    @Override
    public Object getValue() {
        return null;
    }
}

指明瞭類型的實現:對象

class GenericClass implements genericInterface<String, Object> {
    @Override
    public String getKey() {
        return null;
    }

    @Override
    public Object getValue() {
        return null;
    }
}

泛型方法

泛型方法指的是使用泛型的方法。若是這個方法所在的類是個泛型類,直接使用類聲明的參數類型。接口

若是這個方法所在的類不是泛型類或者他想要處理不一樣於泛型類所聲明的參數類型,這時候咱們就須要使用泛型方法。即在方法前加入泛型聲明,方法就能夠直接使用聲明的參數類型。字符串

class GenericClass {

    private Object value;

    public <T> T getValue(){
        return (T)value;
    }

    public void setValue(Object value){
        this.value = value;
    }
}

方法getValue()就是泛型方法,調用代碼以下:get

GenericClass genericClass = new GenericClass();
genericClass.setValue(123);

Integer value = genericClass.getValue();

2、泛型的優勢

數據類型安全

泛型的主要目的經過參數類型檢查,提升JAVA程序數據類型的安全,提前發現錯誤,避免ClassCastException 異常發生。編譯器

List list = new ArrayList();
list.add("test generic");
list.add(123);// 注:123會轉換成Integer對象
list.add(null);

當不實用泛型的時候,上面代碼的使用是被容許的,咱們能夠放入任何對象,當咱們按照某種對象類型去取數據就會出現ClassCastException 異常。

//List<String> list = new ArrayList<String>();
List<String> list = new ArrayList();
list.add("test generic");
//list.add(123);
list.add(null);

List是泛型接口,當咱們這樣使用的時候,「123」這個元素是不被容許使用的。

消除類型轉換

當咱們不使用泛型時,每次取出集合中的元素都須要咱們強制轉換成咱們須要的元素。(Object->Class Type)。

List list = new ArrayList();
list.add("test generic");
String s = (String) list.get(0);

「test generic」存入list是一個Object的對象,取出來是咱們須要轉換成咱們要的字符串String類型。

List<String> list = new ArrayList();
list.add("test generic");
String s = list.get(0);

使用泛型後list.get(0)中取出來的數據類型,就是咱們存入時的String類型。

簡碼,提升效率

經過泛型的應用,作到了簡碼,並且JVM中類文件也相應的減小。JVM幾乎沒有作任何的更改,全部的類型校驗,類型轉換都是在編譯器階段完成。

3、通配符

無限制通配符<?>

定義時不關心或者不肯定實際要操做的數據是什麼類型,可使用無限制通配符(尖括號裏一個問號,即 <?> ),表示能夠持有任何類型。

class GenericClass<T> {
    private T data;
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
    @Override
    public String toString() {
        return "GenericClass{" +
                "data=" + data +
                '}';
    }
}

泛型類定義

public static void print(GenericClass<?> context){
     System.out.println(context);
}

通配符定義的方法參數類型

GenericClass<Integer> integerGenericClass = new GenericClass<>();
integerGenericClass.setData(123);
GenericClass<String> stringGenericClass = new GenericClass<>();
stringGenericClass.setData("123");
print(integerGenericClass);
print(stringGenericClass);

使用時?是一個萬能的類型,T只能是具體的類型

上界通配符 <? extends E>

在類型參數中使用extends表示這個泛型中的參數必須是 E 或者 E 的子類,這樣有兩個好處:

  1. 若是傳入的類型不是E或者E的子類,編輯不成功
  2. 泛型中可使用E的方法,要否則還得強轉成E才能使用
List<? extends Number> list = new ArrayList<Number>(){{add(new Integer(456));add(new Long(456L)); }};
list.add(null);
//list.add(new Integer(123));
//list.add(new Long(123L));
System.out.println(list.size());
Number number = list.get(0);

當使用上邊界通配符時,是不容許往裏存數據的,不肯定具體元素類型。

下界通配符 < ? super E>

在類型參數中使用super表示這個泛型中的參數必須是E或者E的父類。

用於靈活寫入或比較,使得對象能夠寫入父類型的容器,使得父類型的比較方法能夠應用於子類對象。

List<? super C> list = new ArrayList<B>(){{add(new B()); add(new C());}};
list.add(null);
list.add(new C());
list.add(new B());
//list.add(new A());
Object object = list.get(0);

C是B的子類,B是A的子類。當使用下界通配符時,是容許存放E和E的子對象數據的,由於子類對象的引用能夠賦值給父類對象的引用(頂級父類是Object),因此取出來的數據類型是Object.

4、總結

  • 在實例化的時候,就必須聲明泛型具體是一個什麼類型。
  • 使用泛型、通配符提升了代碼的複用性。
  • 把一個對象分爲聲明、使用兩部分的話。泛型側重於類型的聲明上代碼複用,通配符則側重於使用上的代碼複用。泛型用於定義內部數據類型的不肯定性,通配符則用於定義使用的對象類型不肯定性。
  • 若是類型參數在方法聲明中只出現一次,能夠用通配符代替它。
  • 不能同時聲明泛型通配符上界和下界。
相關文章
相關標籤/搜索