文章目錄
-
- 泛型是什麼?
- 泛型對比測試
- 為什麼要使用泛型?
- 使用泛型有什麼好處?
- 怎麼使用泛型?
-
- 泛型類
- 泛型方法
- 泛型類派生出的子類
- 類型通配符
- 泛型擦除
- 應用場景有哪些?
泛型是什麼?
- JDK1.5,引進泛型這個概念。
- 泛型: 在建立對象或者調用方法的時候,再去明确類型。即參數化類型,簡單來說,就是把類型當作一種參數來傳遞,隻不過一般情況下參數寫在()中,而類型寫在<>中。并且在<>中隻能是引用類型。
- 引用類型(reference type): 指向一個對象,而不是原始值,指向對象的變量是引用變量。在java裡面除去基本資料類型的其它類型都是引用資料類型,自己定義的class類都是引用類型,可以像基本類型一樣使用。
- 泛型的設計原則: 隻要在編譯時期沒有出現警告,那麼運作時期就不會出現
異常。ClassCastException
泛型對比測試
- 首先來看不加泛型的情況下,在list集合中添加不同類型的資料,并且在周遊的時候強轉,編譯的時候注定會報
異常的。這就是由于集合中元素類型不統一造成的。ClassCastException
List arrayList = new ArrayList();
//添加一個String類型的元素
arrayList.add("aaaa");
//添加一個Integer類型的元素
arrayList.add(100);
for(int i = 0; i< arrayList.size();i++){
//都強轉成String類型
String item = (String)arrayList.get(i);
Log.d("泛型測試","item = " + item);
}
- 加上泛型之後的,就規定了,這個集合中隻能裝這個類型的元素,要是裝别的,在敲代碼的時候就會報錯,因為你加入的元素,跟規定的類型不一緻,不讓你加。
為什麼要使用泛型?
- 早期用Object來代替任意類型,但是這樣做,有的時候就要進行向下強轉,這樣做不太安全。
- 沒有泛型的話,像
,Collection
這種不限制元素類型的集合,你可以往裡面丟任何元素,并且不會報文法錯誤,但是集合不知道這個元素是什麼類型的,預設都是Map
類型,等你取出來的時候,就給你返Object
類型的,可謂亂丢一時爽,Object
火葬場。get
- 有了泛型呢,就不用強制轉換了,因為你在事先就規定好了,這個集合中裝什麼類型的元素,使代碼更加簡潔。程式也更加健壯(這才是猛男該做得事),因為隻要編譯沒有警告,那麼運作的時候就不會出現
異常了。ClassCastException
使用泛型有什麼好處?
-
上面通過對比已經看出,泛型有哪些好處,這裡在總結一下。
①代碼更簡潔
②程式更健壯
③可讀性和穩定性
④配合增強for循環周遊集合
怎麼使用泛型?
泛型類
- 把泛型定義在類上,也可以定義在方法上,在使用該類或者方法的時候,才根據自己的需要,将類型明确下來。注意: 類上聲明的泛型,隻對非靜态成員有效。
1.定義
//把泛型定義在類上
public class ObjectTool<T>{
private object;
public T getObj(){
return object;
}
public void setObj(T object){
this.object=object;
}
}
2.使用
public static void main(String[] args){
//建立對象,并指定其元素類型(這裡是String型)
ObjectTool<String> tool1 = new ObjectTool<>();
tool1.setObj(new String("張三"));
String s=tool.getObj();
System.Out.println(s);
//建立對象,并指定其元素類型(這裡是Integer型)
ObjectTool<Integer> tool2 = new ObjectTool<>();
tool2.setObj(10);
int i=tool2.getObj();
System.Out.println(i);
}
泛型方法
- 如果外界僅僅對一個方法感興趣,而不關心類中的其他屬性,那麼将泛型定義在類上就有些小題大做,這裡直接定義在方法上,精準打擊!!
1.定義泛型方法
public <T> void show(T t){
System.Out.println(t);
}
2.泛型方法的使用
public static void main (String[] args){
//建立對象
ObjectTool obj = new ObjectTool();
//調用方法,傳進來什麼類型,傳回值就是什麼類型
obj.show("hello");
obj.show(4);
obj.show(false);
}
泛型類派生出的子類
- 換上馬甲他還是王八,雖然加了泛型,但說到底,他還是個類,既然是個類,那麼他就可以被繼承。然而泛型類的繼承也分兩種。
①子類明确泛型類的類型參數變量(泛型接口)
//把泛型定義在接口上
public interface Inter<T> {
public abstract void show(T t);
}
//子類明确泛型類的類型參數變量:
public class InterImpl implements Inter<String> {
@Override
public void show(String s) {
System.out.println(s);
}
}
②子類不明确泛型類的類型參數變量
- 此時,外界使用子類的時候,也需要傳遞類型參數變量進來,在實作類上需要定義出類型參數變量。
//實作類要定義出<T>類型
public class InterImpl<T> implements Inter<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
類型通配符
- 問題: 方法接收一個集合參數,周遊集合并把集合元素列印出來
普通解決辦法:
public void test(List list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
加類型通配符?
public void test(List<?> list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
-
就加了一個問号?,能有什麼作用
答案是:更優雅~
- 還有一個問題是設定通配符上限和下限。這個問題很繞,搞不清楚,當然,大多時候,使用泛型方法來替代通配符,條條大路通羅馬嘛。
- 注意:加了?就隻能調用與對象無關的方法,不能調用對象與類型有關的方法。因為直到外界使用才知道具體的類型是什麼。也就是說,在上面的List集合,是不能使用add()方法的。因為add()方法是把對象丢進集合中,而現在不知道對象的類型。
泛型擦除
- 因為泛型是提供給javac編譯器使用的,它用于限定集合的輸入類型,讓編譯器在源代碼級别上,即擋住向集合中插入非法資料。但編譯器編譯完帶有泛形的java程式後,生成的class檔案中将不再帶有泛形資訊,以此使程式運作效率不受到影響,這個過程稱之為“泛型擦除”。這一點應用在相容老版本上,因為JDK1.5之前沒有泛型,當把帶有泛型特性的集合指派給老版本的集合時候,就會把泛型擦除掉,amazing!
應用場景有哪些?
- 場景一: 最常用的還是應用于限制集合的參數類型。
- 場景二: 項目中,每次都要寫好幾個DAO,會顯得臃腫。
- 優化辦法–抽象DAO: 在抽象DAO中,是不知道哪一個DAO會繼承它,是以是不知道其具體的類型的。而泛型就是在建立的時候才指定其具體的類型。
抽象DAO
public abstract class BaseDao<T> {
private Session session;
private Class clazz;
//哪個子類調的這個方法,得到的class就是子類處理的類型(非常重要)
public BaseDao(){
Class clazz = this.getClass(); //拿到的是子類
ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass();
//BaseDao<Category>
clazz = (Class) pt.getActualTypeArguments()[0];
System.out.println(clazz);
}
public void add(T t){
session.save(t);
}
public T find(String id){
return (T) session.get(clazz, id);
}
public void update(T t){
session.update(t);
}
public void delete(String id){
T t = (T) session.get(clazz, id);
session.delete(t);
}
}
繼承抽象DAO
public class CategoryDao extends BaseDao<Category> {
将抽象DAO中的方法繼承了下來
@override
...
...
...
}
public class BookDao extends BaseDao<Book> {
@override
...
...
...
}