1)泛型是什麼:
是一種未知的數據類型,當我們不知道使用什麼數據類型時,可以使用泛型。
泛型也可以看作是一個變量,用來接收數據類型。
E e:Element 元素
T t:Type 類型
2)使用泛型解決的問題:
解決向下轉型帶來的類轉換異常(ClassCastException)。
3)使用泛型的好處:
●避免了類轉換的麻煩,存儲的是什麼類型,取出的就是什麼類型。
●把運行期異常提升到了編譯期異常。
弊端:不使用泛型時能存儲任意類型的數據。(不適用默認則爲Object)
public class Test {
public static void main(String[] args) {
// show1();
show2();
}
//不使用泛型
public static void show1() {
//數組不適用泛型則爲默認類型,爲Object
ArrayList list = new ArrayList();
list.add(1);
list.add("abc");
//迭代輸出
Iterator it = list.iterator();
while (it.hasNext()){
Object obj = it.next();
System.out.println(obj);
//調用String特有的方法,Length獲取長度
//向下轉型,會拋出異常,不能把Integer類型轉換爲String類型
String s =(String) obj ;
System.out.println(s.length());
}
}
//使用泛型
public static void show2(){
ArrayList<String> list =new ArrayList<>();
list.add("Aaa");
list.add("Bbb");
list.add("Ccc");
//list.add(123); 報錯
//迭代輸出
for (String str : list){
System.out.println(str);
}
}
}
4)含有泛型的類:
使用泛型後,所有類中屬性的類型都是動態設置。即創建對象時是什麼類型,泛型就是什麼類型。
//含有泛型的類
public class GenericClass <E> {
public E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
public class doMain {
public static void main(String[] args) {
GenericClass<String> gc1 = new GenericClass<>();
gc1.setName("String類型");
GenericClass<Integer> gc2 = new GenericClass<>();
gc2.setName(1);
}
}
如果不使用泛型,我們就只能使用一種數據類型。(Object除外,使用Object則會帶來安全隱患問題)
5)含有泛型的方法:
定義在方法的修飾符和返回值之間。
作用:調用方法時,傳遞什麼類型,泛型就是什麼類型。
格式:
修飾符 <泛型> 返回值類型 方法名(參數列表(使用泛型)){
方法體;
}
public class GenericMethod {
//含有泛型的方法
public <T> void method(T t){
System.out.println(t);
}
//含有泛型的靜態方法
public static <S> void method2(S s){
System.out.println(s);
}
}
public class doMain {
public static void main(String[] args) {
GenericMethod gm = new GenericMethod();
gm.method(10);
gm.method("abc");
gm.method(13);
GenericMethod.method2("靜態方法");
GenericMethod.method2("2");
}
}
6)含有泛型的接口:
//含有泛型的接口
interface IGeneric<I> {
public abstract void method(I i);
}
實現方式一:
實現類繼續設置泛型標記。
class IGenericImpl<I> implements IGeneric <I>{
@Override
public void method(I i) {
System.out.println(i);
}
}
實現方式二:
class IGenericImpl2 implements IGeneric<String>{
@Override
public void method(String s) {
System.out.println(s);
}
}
一和二的差別:
有沒有爲子類設置具體的泛型。
public class doMain {
public static void main(String[] args) {
IGenericImpl gil = new IGenericImpl();
gil.method("使用泛型接口的實現類1");
gil.method(1);
IGenericImpl2 gil2 = new IGenericImpl2();
gil2.method("使用泛型接口的實現類2");
}
}
7)泛型的通配符:
<?>解決的是參數傳遞的問題。
它只能夠接收數據,不能夠存儲數據。
public class Generic {
public static void main(String[] args) {
ArrayList<Integer> list01 =new ArrayList<>();
list01.add(1);
list01.add(2);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArray(list01);
printArray(list02);
//它只能夠接收數據,不能夠存儲數據
//ArrayList<?> list03 = new ArrayList<?>();報錯
}
//定義一個方法,能遍歷所有類型的ArrayList集合。
//這時候我們不知道ArrayList集合使用什麼數據類型,可以用泛型的通配符 ? 來接收數據類型
// public static void printArray(ArrayList<String> list){
public static void printArray(ArrayList<?> list){
Iterator<?> it = list.iterator();
while (it.hasNext()){
Object obj =it.next();
System.out.println(obj);
}
}
}
注意:在明確設置一個類爲泛型類型時,沒有繼承關係的概念。
public static void printArray(ArrayList<String> list){
public static void printArray(ArrayList<Object> list){
雖然Object與String類是父子類的關係,但換到泛型中就屬於兩個完全獨立的概念。
通配符的高級使用——受限泛型
●泛型的上限:
格式:類名 <? extends 類 > 對象名,可以在方法聲明和參數上使用。
作用:只能夠接收該類型及其子類。
●泛型的下限:
格式:類名 <? super 類 > 對象名,可以在方法參數上使用。
作用:只能夠接收該類型及其父類。
public class doMain {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<>();
Collection<String> list2 = new ArrayList<>();
Collection<Number> list3 = new ArrayList<>();
Collection<Object> list4 = new ArrayList<>();
getElement1(list1);
getElement1(list2);//報錯
getElement1(list3);
getElement1(list4);//報錯
getElement2(list1);//報錯
getElement2(list2);//報錯
getElement2(list3);
getElement2(list4);
}
//泛型的上限:此時的泛型?,必須是Number類或其類型的子類
public static void getElement1(Collection<? extends Number> coll){}
//泛型的下限:此時的泛型?,必須是Number類或其類型的父類
public static void getElement2(Collection<? super Number> coll){}
}