泛型是什么
所謂“泛型”,就是“寬泛的數(shù)據(jù)類型”,任意的數(shù)據(jù)類型。
我們?yōu)槭裁匆褂梅盒湍?數(shù)據(jù)類型為什么要使用"寬泛"的?
設想一下 , 如果我們沒有泛型 , 那么我們在使用List的時候, 經(jīng)常使用到的操作就是存和取 , 但是我們因為不能指定泛型 , 所以只能存入Object類型.
- 存數(shù)據(jù)
list.add(new Person());
恩 , 沒有多大的影響 , 轉型操作讓我們很舒服 , 但是取數(shù)據(jù)就沒這么方便了 - 取數(shù)據(jù)
Person p = (Person) list.get(0)
每次取出數(shù)據(jù)都要先進行強制類型轉換 , 轉來轉去的很快你就會迷糊 .
所以 , 我們現(xiàn)在引入了泛型之后 , 對于List的操作就方便多了
隨便說一下
其實 , 在Java中使用的泛型也不是真正意義上的泛型 , 因為我們在編譯之后 , 再反編譯回java代碼的話 , 可以看到編譯器自動的把我們的泛型操作還原回了強制類型轉換 , 所以我們吧java中的泛型叫做偽泛型 , 把它當做語法糖就好,
泛型使用
首先準備好我們的測試對象Box:
public class Box<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
- 直接使用泛型
這種方式就像普通的List一樣 , 規(guī)定了數(shù)據(jù)結構之后 , 直接使用 .
Box<Number> b=new Box<>();
b.setData(new Double(1.1));
Number data = b.getData();
我們也可以在源碼中找到類似的使用:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
其實這種方式和直接使用Object挺像的 , 只是略微靈活了一些 . 但是這就滿足了么? 我們可以使用另外一種更舒服更優(yōu)雅的方法
public ArrayList(Collection<? extends E> c) {
... ...
}
- 設置類型上限<? extends Number>
用這種方法 , 就可以限定使用泛型的上限了 , 什么叫上限呢 , 就是繼承關系的小于 , 不是小于等于 拿ArrayList來舉例子
public class ArrayList<E> extends AbstractList<E>
首先,在ArrayList的類定義中就生命了使用泛型E , 那么我們在實例化的時候 , 就規(guī)定了E的實際類型 .
public boolean addAll(int index, Collection<? extends E> c) {
if (index < 0 || index > this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
int cSize = c.size();
if (cSize==0)
return false;
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
parent.addAll(parentOffset + index, c);
this.modCount = parent.modCount;
this.size += cSize;
return true;
}
addAll方法中 , 有這樣一個限定<? extends E> , 也就是說 , addAll方法允許接收一個集合 , 集合的泛型類型必須是E的子類 . 但必須注意的是 , 這里設置了類型的上限 , 如果超出上限的話 ,會拋出異常的 .
- 設置類型下限<? super Number>
這個和第二點正好相反 , 限定了泛型的類型下限(好像沒見過這么玩的)
父類的引用可以指向子類的實例 , 子類的引用無法指向父類的實例
Box<? super Number> box=new Box<>();
box.setData(new Object());
/**
*這里會報錯 , 因為Object為Number的父類 , 雖然限定了? super Number ,但作為參數(shù) ,
*子類無法指向父類的應用, 即Object不能當成Number使用
**/
box.setData(new Integer(1));
/**
*這里與上面恰好相反 , Integer可以當成Number使用 , 編譯通過
*/
乍一看好像有點亂是吧 , 其實在泛型的默認規(guī)范中 , 如果破壞了這個規(guī)范 , 那么使用泛型就沒有太大的意義了
- extends , 適用于get()方法 , 用來限制返回值類型
- super 適用于set()方法 , 用來限制參數(shù)類型