泛型概述
泛型是JDK5中引入的特性,可以在編譯階段約束操作的數據類型,并進行檢查。
泛型的格式:<數據類型>
注意:泛型只能支持引用數據類型。
泛型的好處
沒有泛型的時候,可以往集合中添加任意類型的數據,默認將集合中所有元素的數據類型都提升為Object類型,但是在獲取數據的時候,數據都是Object類型,所以無法直接使用原來類型的特有方法,需要進行強轉,如果不知道該強轉成什么數據類型就沒辦法了。
此時推出了泛型,可以在添加數據的時候就把類型進行統一。
而且我們在獲取數據的時候,也省的強轉了,非常的方便。?
泛型的細節
1.泛型中不能寫基本數據類型
2.指定泛型的具體類型的集合,添加數據時,可以添加該類類型或者其子類類型的數據
3.如果不寫泛型,類型默認是Object?
泛型的分類
在類后面定義泛型為泛型類
在方法上面定義泛型為泛型方法
在接口后面定義泛型為泛型接口?
泛型類
使用場景
當一個類中,某個變量的數據類型不確定時,就可以定義帶有泛型的類
格式
修飾符 class 類名 <類型> {
? ? ? ? ...
}
舉例
public class MyArrayList <E>?{
? ? ? ? ...
}此處E可以理解為變量,但是不是用來記錄數據的,而是記錄數據的類型,常用T、E、K、V字母表示,創建該類對象時,E就確定類型
如果該類要使用多種類型的數據,可在<>中寫多種變量通過逗號分隔,例如<E,T,K>
代碼演示?
要求:定義一個類實現ArrayList中的部分方法?
import java.util.Arrays;//定義一個類實現ArrayList中的部分方法
public class MyArrayList<E>{//成員變量private Object[] obj = new Object[10];private int size;public MyArrayList() {}//添加元素方法public boolean add(E e){obj[size] = e;size++;return true;}//get方法public E get(int i){return (E)obj[i];}@Overridepublic String toString() {return obj.toString();}
}
測試類
public class Test {public static void main(String[] args) {MyArrayList<String> mal1 = new MyArrayList<>();mal1.add("aaa");mal1.add("bbb");System.out.println(mal1.get(1));//bbbMyArrayList<Integer> mal2 = new MyArrayList<>();mal2.add(1);mal2.add(2);System.out.println(mal2.get(1));//2}
}
?
泛型方法
使用場景
當一個方法,某個變量的數據類型不確定時,就可以定義帶有泛型的方法
格式
修飾符 <類型> 返回值類型 方法名(類型 變量名){
? ? ? ? ...
}
舉例
public <E> void show(E e){
? ? ? ? ...
}
調用該方法時E就確定類型
代碼演示
定義一個工具類:ListUtil,類中定義一個靜態方法addAll,用來添加多個集合的元素。
import java.util.ArrayList;
//定義一個工具類:ListUtil
//類中定義一個靜態方法addAll,用來添加多個集合的元素。
public class ListUtil {private ListUtil() {}public static <E> void addAll1(ArrayList<E> list, E e1, E e2) {list.add(e1);list.add(e2);}//參數個數不確定時使用E...epublic static <E> void addAll2(ArrayList<E> list, E... e) {for (E element : e) {list.add(element);}}}
?測試類
import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList<String> list1 = new ArrayList<>();ListUtil.addAll1(list1, "aaa", "bbb");System.out.println(list1);//[aaa, bbb]ArrayList<Integer> list2 = new ArrayList<>();ListUtil.addAll2(list2, 1, 2, 3, 4);System.out.println(list2);//[1, 2, 3, 4]}
}
細節
泛型類和泛型方法泛型方法都能解決方法中形參類型不確定的問題
區別:
使用類名后面定義的泛型:所有方法都能用
在方法申明上定義自己的泛型:只有本方法能用
泛型接口
使用場景
定義在接口名后面,表示接口實現類的類型
如何使用一個帶泛型的接口
方式1:
實現類給出具體類型
方式2:
實現類延續泛型,創建對象時再確定
?
泛型的通配符
泛型不具備繼承性,但是數據具備繼承性。
指定泛型的具體類型的集合,添加數據時,可以添加該類類型或者其子類類型的數據
但是調用方法時,形參的泛型里面寫的是什么類型,那么只能傳遞什么類型的數據
此時我們就可以使用泛型的通配符:
?也表示不確定的類型
? extends E:表示可以傳遞E或者E所有的子類類型
? super E:表示可以傳遞E或者E所有的父類類型?
練習
?
測試類中定義一個方法用于飼養動物
public static void keepPet(ArrayList<???> list){
????????//遍歷集合,調用動物的eat方法
}
要求1:該方法能養所有品種的貓,但是不能養狗
要求2:該方法能養所有品種的狗,但是不能養貓
要求3:該方法能養所有的動物,但是不能傳遞其他類型
import java.util.ArrayList;public class Test {public static void main(String[] args) {ArrayList<PersianCat> list1 = new ArrayList<>();ArrayList<LiHuaCat> list2 = new ArrayList<>();ArrayList<TeddyDog> list3 = new ArrayList<>();ArrayList<HuskyDog> list4 = new ArrayList<>();keepPet(list1);keepPet(list2);keepPet(list3);keepPet(list4);}//測試類中定義一個方法用于飼養動物//要求1:該方法能養所有品種的貓,但是不能養狗//public static void keepPet(ArrayList<? extends Cat> list) {}//要求2:該方法能養所有品種的狗,但是不能養貓//public static void keepPet(ArrayList<? extends Dog> list) {}//要求3:該方法能養所有的動物,但是不能傳遞其他類型public static void keepPet(ArrayList<? extends Animal> list) {}
} abstract class Animal {public abstract void eat();}abstract class Cat extends Animal {}abstract class Dog extends Animal {}class PersianCat extends Cat {@Overridepublic void eat() {System.out.println("波斯貓吃東西");}}class LiHuaCat extends Cat {@Overridepublic void eat() {System.out.println("貍花貓吃東西");}}class TeddyDog extends Dog {@Overridepublic void eat() {System.out.println("泰迪狗吃東西");}}class HuskyDog extends Dog {@Overridepublic void eat() {System.out.println("哈士奇吃東西");}}
?