
泛型
什么是泛型?為什么使用泛型?
泛型的出現意味著編寫的代碼可以被不同類型的對象所重用,提升了代碼的重用性。泛型的本質是參數化類型,即將所需操作的數據類型設置為一個參數。 舉個實際中的栗子:我們需要設計一個柜子的類,柜子可以用于存放書本、食品或者衣物,但是我們在設計階段不能確定柜子里具體要存放什么東西,那怎么來設計這樣一個通用型的柜子,這里就可以用到泛型。所以,我們把存放元素的類型設計成一個參數,這個類型參數就稱之為泛型。 舉個JAVA中的栗子:ArrayList,List,這個就是類型參數,也就是泛型。為什么這么寫呢?因為我們在創建Arraylist或者List時,無法確定里面具體存儲的元素的類型,但是我們有希望一個實例對象中存儲的元素的類型時一致的,這就需要泛型來實現操作。
int[] arr1 = new int[] {159,357,456};//沒有用泛型,ArrayList中存儲的元素格式各樣,實際開發中在操作時是很容易出現問題的List list1 = new ArrayList();list1.add(123);list1.add("敲代碼的阿茄");list1.add(arr1);//使用泛型,限制ArrayList存放的元素的類型,就不能添加存儲其他類型的元素了List<String> list2 = new ArrayList<>();list2.add("敲");list2.add("代");list2.add("碼");list2.add("的");list2.add("阿");list2.add("茄");//list2.add(123);//無法添加//list2.add(arr1);//無法添加
泛型使用的基本要求
- 異常類不能聲明為泛型。
- 泛型不能是基本數據類型,需要使用基本數據類型的泛型可以寫成其包裝類。
//List<int> list2 = new ArrayList<>();List<Integer> list2 = new ArrayList<>();
自定義泛型類
在類或接口中聲明的泛型,可以作為非靜態屬性的類型、非靜態方法的參數類型、非靜態方法的返回值。但是,不能在靜態方法中使用類的泛型。
// 泛型類:類中定義有不確定的類型public class Dict<T> {String dictName;int dictCount;T dictT;//泛型類下用了泛型的方法,報錯,需要去掉static//public static void get(T dictT) {// this.dictT = dictT;//}//泛型類下沒用泛型的方法public static void set() {System.out.println("");}}
泛型方法和泛型類下的方法?
泛型方法:該泛型方法所在的類可以不是泛型類。往直觀一點講,方法中出現了泛型結構<>。 那么,泛型方法可以是靜態的嗎?可以,因為泛型參數是在調用方法時確定的,并非在實例化時確定的。
public class GenericTest {public static void main(String[] args) {Dict<Float> dict = new Dict<>();dict.set1(0.0f);//調用泛型方法,泛型類型跟類的泛型沒關系,不受影響dict.set2(" ");dict.set2(36);dict.set2(new ArrayList());}}//泛型類class Dict<T> {String dictName;int dictCount;//泛型類中的方法:如果調用了泛型則不能為靜態public void set1(T dictT) {System.out.println("我是泛型類下的方法");}//泛型方法:可以為靜態public static <T> void set2(T dictT) {System.out.println("我是泛型方法");}}
泛型與繼承
- 如果類A是類B的父類,但是,
G<A>
不是G<B>
的父類(G是類或者接口),兩個屬于不同的類。所以不存在兩者間的多態和向上轉型。 - 但是呢,
A<G>
仍然是B<G>
的父類。
通配符
通配符:?
- 利用通配符,創建二者的共同父類,
G<A>
和G<B>
的共同父類G<?>
; - 但是,不能往其中添加新數據,常用于賦值操作而已,僅能添加
null
; - 允許讀取數據,讀取數據的類型為object;
舉例說明:定義List<?>
是List<Object>
和List<String>
的公共父類。
//不能添加數據,除了nullList<?> list = new ArrayList<>();//list.add(16);//報錯//list.add(" ");//報錯list.add(null);//允許讀取數據List<?> list = new ArrayList<>();List<String> list1 = new ArrayList<>();list1.add("newstring");list =list1;list.add(null);Object obj = list.get(0);System.out.println(obj);//newstring
有限制條件的通配符
G<? extends A>
可以作為G<A>
和G<B>
的父類,其中B是A的子類;即,可以作為所有繼承于A類的類G<A的子類>
的父類。G<? super A>
可以作為G<A>
和G<B>
的父類,其中B是A的父類;即,可以作為所有A的父類的G<A的父類>
的父類。
// 下面舉例類的關系:Earth extends Sun, Sun extends UniverseList<? extends Sun> list1 = new ArrayList<>();// 可以作為List<Sun及其子類>的父類List<? super Sun> list2 = new ArrayList<>();// 可以作為List<Sun及其父類>的父類List<Universe> list3 = new ArrayList<>();List<Sun> list4 = new ArrayList<>();List<Earth> list5 = new ArrayList<>();list1 = list4;// 多態list2 = list4;//多態// 讀取數據Sun s1 =list1.get(0);//獲取的數據是Sun或者Sun的子類的對象,可以實現多態Earth e1 =(Earth)list1.get(0);//不強轉會報錯,因為獲取的數據可能是Sun的對象,父類轉子類需要強轉Sun s2=(Sun)list2.get(0);//不強轉會報錯,獲取的數據可能是Sun的父類,父類轉子類需要強轉Object o=list2.get(0);//不強轉情況下,只能是Object// 寫入數據list2.add(new Sun());//只能添加Sun本身,或者Sun的子類//因為list2存的可能是Sun及其父類,假設new的是Universe,但是list2中存儲的是Sun,//即實際?=Sun,那么Universe作為父類是無法直接賦給子類的list2.add(new Earth());//list1.add();//無法添加數據,因為你無法確定存儲的子類有多小