泛型
泛型由來
泛型字面意思不知道是什么類型,但又好像什么類型都是。看前面用到的集合都有泛型的影子。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
...
}
以ArrayList為例,它為什么要寫成ArrayList<E>這樣.我也不知道他為什么要寫成這樣,但是我知道如果它不用泛型,那代碼就亂了,那也別寫代碼了。
-
ArrayList運用泛型可以這么寫
ArrayList<String> strings = new ArrayList<>();//可以存String ArrayList<Integer> integers = new ArrayList<>();//可以存Integer類型 ArrayList<Object> objects = new ArrayList<>();//可以存對象
-
ArrayList沒用泛型之后:
如果要存放各種各樣的樣類型,是不是意味著寫各種各樣對象的鏈表,那開發者可以不用活了...咦,或者你可以可不用死了,你發現所有類都繼承自Object類,那只要這么寫一個
在取出元素的時候強轉成對應的類型就可以了,是的,這樣就可以不會被寫代碼累死了。但為什么源碼沒有這么寫,因為它沒泛型強大!讓我們看下面代碼了解泛型的由來。
假如我要寫一個類存放一個int類型的模型,那簡單
public class IntegerFun {
private int data;
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
滿足你的需求,但需求變了,我還要一個存放String類型的,那你也忍了,再來一個
public class StringFun {
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
需求又添加了一個,存放Long、Student、Math.....于是撕逼開始...結束之后,這次你聰明了,寫了一個萬能的,管它存放什么都行的類:
public class ObjectFun {
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
這樣總算解決了問題,看用法:

你總覺得你寫的前無故人,后無來者了,可是經理還是過來找你了,因為你的程序跑不起來了,你認真的看了一下,發現代碼第十五行,存放的是Integer 結果你轉成了Float出錯了,那你可能會抱怨編譯器
沒有立即告訴你這里存在問題,接下來我們來看看運用泛型會怎么樣。
public class Fun<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
用法:

這就是使用泛型的原因.
多泛型
上面寫的還不夠全,因為Fun<T>只能存放一種類型的元素,假如我要存放多種呢,我希望你已經會了,再來一個泛型。
/**
* 泛型類
*
* @param <T>泛型T
* @param <V>泛型V
*/
public class Fun<T, V> {
private T data;
private V data2;
//泛型方法
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public V getData2() {
return data2;
}
public void setData2(V data2) {
this.data2 = data2;
}
}
要存放無數個呢.....
Fun<T,T1,T2,T3,.,.>{
}
泛型規范
T1,T2,T3,.......泛型可以隨便寫嗎,可以隨便寫,但我們追求規范。
- E — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>
- K,V — Key,Value,代表Map的鍵值對
- N — Number,數字
- T — Type,類型,如String,Integer等等
泛型接口,泛型類,泛型方法
-
泛型接口
/** * 格式:接口名后面跟 <T> * * @param <T> */ public interface IManager<T> { void add(T data); T remove(int index); void sop(); }
泛型類(之前的都是)
-
泛型類實現泛型接口(關于怎么更好的構建泛型類,就靠諸君在日后的生涯中尋找答案了)
/** * @param <T> */ public class Manager<T> implements IManager<T> { private List<T> datas; public Manager() { datas = new ArrayList<>(); } @Override public void add(T data) { datas.add(data); } @Override public T get(int index) { return datas.get(index); } @Override public void sop() { for (T t : datas) { System.out.println(t); } } }
-
泛型方法(前面的好多)
@Override public T get(int index) { return datas.get(index); } //泛型方法 public T getData() { return data; }
案例運行
public class Demo {
public static void main(String[] args) {
Manager<Student> manager = new Manager<Student>();
manager.add(new Student("小魚", 20));
manager.add(new Student("小黑", 30));
manager.add(new Student("SF", 21));
System.out.println("get--->" + manager.get(1));
manager.sop();
}
}
泛型能代表的太多了,是否能給它一些限制呢,答案也是肯定的。下面來看泛型的上下限。
確定上限
什么叫確定上限,字面意思就是你的上限我已經給你定好了,你不可能再超出這個范圍,那就有用到一個關鍵字 extends,我們讓 T(泛型)extends 某一個類,那是不是這個泛型的上限就被你決定了。
下面我們看代碼。
-
定義基類
/** * 基類 */ public class Person { int age; String name; public Person(String name, int age) { this.name = name; this.age = age; } }
-
定義子類
public class Child extends Person { public Child(String name, int age) { super(name, age); } }
-
還有一個不相關的類
public class Dog { private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } }
-
定義泛型類
public class Fun1<T extends Person> {//確定上限,(泛型類的建模很重要) private T datas; public T getDatas() { return datas; } public void setDatas(T datas) { this.datas = datas; } }
-
運行(接收的引用類型要么是Person類,要么是Person的子類: 確定上限)
確定下限
感覺用的不多,關鍵字 super
案例
public class Demo {
public static void main(String[] args) {
Collection<Student> cs = new ArrayList<Student>();
cs.add(new Student("李xx", 20));
cs.add(new Student("xxx", 19));
cs.add(new Student("hhahah", 20));
sop2(cs);
}
//接收的引用類型要么是Student類,要么是Student的父類: 確定下限
static void sop2(Collection<? super Student> cs) {
Iterator<?> iterator = cs.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
讓我們帶著泛型的目光回顧 TreeSet中涉及Collections、Comparator、Comparable
我們說過TreeSet存儲的元素是要支持可排序的,那他有兩種方式,一是實現Comparable接口,二是在構造TreeSet實例的時候傳一個Comparator實例。
我們先看源碼:
-
Comparable
package java.lang; public interface Comparable<T> {//一個泛型接口 int compareTo(T var1); }
這就是Comparable所有的代碼,簡單吧.
-
Comparator代碼巨多,我們也就只看一行
public interface Comparator<T> { int compare(T var1, T var2); ...... }
和Comparable很像;
-
Collections集合工具類,代碼巨多,我們也就只看幾行
public static <T extends Comparable<? super T>> void sort(List<T> var0) { var0.sort((Comparator)null); } public static <T> void sort(List<T> var0, Comparator<? super T> var1) { var0.sort(var1); }
當初也許你會很好奇,這個類憑什么幫你排序,現在你知道了吧,你所傳的實例都被泛型限定好了,這里出現了一個以前沒說過的"?"號,我們先忽略它。
兩個sort方法,要么實現Comparable,要么是Comparator,但有一點他們是統一的,就是都是用確定下限的泛型方式。加深印象!
案例 Comparator泛型的確定下限
-
Animal(基類)
public class Animal { int age; String name; public Animal(int age, String name) { this.age = age; this.name = name; } @Override public String toString() { return "[" + this.name + "\t" + this.age + "]"; } }
-
Cat(子類)
public class Cat extends Animal { public Cat(int age, String name) { super(age, name); } @Override public String toString() { return super.age + ""; } }
-
運行
還有一個?號等著去解決...
? 通配符
我們在Collections 的源碼中看到了好多Comparable<? super T>,那這個?和T有什么關系呢。
? 和T沒有什么必然的聯系。我們要使用T,則必須在定義類的時候申明T,像 class Fun<T>,然后在類里可以使用T這一類型,
而?則表示通配(填充),表示通配,表示通配,而不是定義,因此我們使用之前不用定義它,表示通配!就如 Class<?> cls = Person.class.getClass();
Class<T>在實例化的時候,T要替換成具體類
Class<?>它是個通配泛型,?可以代表任何類型
<? extends T>受限統配,表示T的一個未知子類。
<? super T>下限統配,表示T的一個未知父類。