二分查詢 & 網線切割
阿新 • • 發佈:2020-12-20
目錄
泛型(generics)
前言
出現的原因:想讓一個類可以用於所有型別,但是我們在以前定義的時候,只能定義一種型別,於是就出現了泛型。
泛型使用
我們可以看看 Java 定義的 List 介面的使用。
import java.util.ArrayList; import java.util.List; public class GenericTest { public static void main(String[] args) { // 指定型別 ,list 只能儲存 String 元素,告訴 Java 這個 List 只能有 String 元素 List<String> strList = new ArrayList<>(); strList.add("str1"); strList.add("str2"); strList.add("str3"); strList.forEach(System.out::println); } }
上面的 List 的引用指向的是 ArrayList 物件,我們看一下 ArrayList 中的 add 方法定義。
看一下 ArrayList 的 add 方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
可以看到要新增的元素型別是 E,那麼這個 E 來自哪裡呢?我們看一下 ArrayList 的定義:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
我們建立物件時是這樣的:
List<String> strList = new ArrayList<>();
也就是說,這個 E 就是我們在建立 ArrayList 物件時放入的型別,通過看 add 方法我們發現,要新增的元素也必須是這個型別。
當然別的類不一定是這樣,要根據泛型的定義來判斷使用的方式,具體情況,具體分析。
如何定義一個泛型
將型別定義在類後面的尖括號 ,可以定義多個。
public class MyGenericType1<MyType1, MyType2> { private MyType1 type1; private MyType2 type2; }
其實泛型就是型別擦除,然後在呼叫的時候,幫我們做強制型別轉換。如果出現錯誤,報錯資訊會顯示在呼叫的那一行。
協變和逆變
協變和逆變都是針對引用型別的,不能用於建立物件型別,在建立物件時必須指定一個明確型別。
協變
List<? extends Person> persons = null;
這種形式就是協變,使用協變時,類必須是 ? extends
後面的類本身或其子類。
逆變
List<? super Student> person2s = null;
這種形式就是逆變,使用逆變時,類必須是? super
後面的類本身或其父類。
import java.util.ArrayList;
import java.util.List;
public class GenericTest {
public static void main(String[] args) {
// 指定型別 ,list 只能儲存 String 元素,告訴 Java 這個 List 只能有 String 元素
// 協變:類必須是 ? extends 後面的類本身或其子類
List<? extends Person> persons = null;
// 不可以加入(List並沒有記住是什麼型別,需要指定明確的型別)
// persons.add(new Person());
// persons.add(new Student());
persons = new ArrayList<Person>();
persons = new ArrayList<Student>();
// 逆變:類必須是 ? super 後面的類本身或者其父類類
List<? super Student> person2s = null;
person2s = new ArrayList<Person>();
person2s = new ArrayList<Student>();
}
}
寫入使用逆變,讀取使用協變。可以參考 Java 類庫中的方法。
泛型總結
泛型最重要的就是這兩點。
- 編譯器檢查並進行型別擦除。
- 使用時會進行型別強制轉換。