美滋滋!教會了公司小姐姐Java中泛型如何使用,她現在要加我微信了!
阿新 • • 發佈:2021-03-04
一、什麼是泛型?
1.泛型是一種未知的資料型別,當我們不知道使用什麼資料型別的時候,可以使用泛型。 2.泛型也可以看作是一個變數,用來接收資料型別(注意接收的是資料型別)。
E e:Element 元素
T t:Type 型別
複製程式碼
例如:ArrayList集合在定義的時候,不知道集合中都會儲存什麼型別的資料,所以型別使用泛型。
public class ArrayList<E> {
public boolean add(E e) {}
public E get(int index){}
}
複製程式碼
建立集合物件的時候,就會確定泛型的資料型別
二、泛型的好處
建立集合物件,使用泛型
好處:
- 避免了型別轉換的麻煩,儲存的是什麼型別,取出的就是什麼型別;
- 把執行期異常(程式碼執行之後會丟擲的異常),提升到了編譯期(寫程式碼的時候會報錯);
弊端:
- 泛型是什麼型別,只能儲存什麼型別的資料;
private static void show01() { ArrayList<String> list = new ArrayList<>(); list.add("abc"); list.add(1);//報錯:add(java.lang.String)in ArrayList cannot be applied to (int) //使用迭代器遍歷list集合 Iterator<String> it = list.iterator(); while(it.hasNext()){ String s = it.next(); System.out.println(s+"->"+s.length()); } } 複製程式碼
建立集合物件,不使用泛型
好處:集合不使用泛型,預設的型別就是Object型別,可以儲存任意型別的資料;
弊端:不安全,會引發異常;
private static void show02() { ArrayList list = new ArrayList(); list.add("abc"); list.add(1); //使用迭代器遍歷list集合 //獲取迭代器 Iterator it = list.iterator(); //使用迭代器中的方法hasNext和next遍歷集合 while(it.hasNext()){ //取出元素也是Object型別 Object obj = it.next(); System.out.println(obj); //想要使用String類特有的方法,length獲取字串的長度;不能使用 多型 Object obj = "abc"; //需要向下轉型 //會丟擲ClassCastException型別轉換異常,不能把Integer型別轉換為String型別 String s = (String)obj; System.out.println(s.length()); } } 複製程式碼
三、泛型的定義與使用
1.定義使用含有泛型的類
/**
定義一個含有泛型的類,模擬ArrayList集合
泛型是一個未知的資料型別,當我們不確定什麼什麼資料型別的時候,可以使用泛型
泛型可以接收任意的資料型別,可以使用Integer,String,物件Student...
建立物件的時候確定泛型的資料型別
*/
public class GenericClass<E>{
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
複製程式碼
使用該類
public class DemoGenericClass {
public static void main(String[] args) {
//不寫泛型預設為Object型別
GenericClass gc = new GenericClass();
gc.setName("只能是字串");
Object obj = gc.getName();
System.out.println(obj);
GenericClass<Integer> gc2 = new GenericClass<>();
gc2.setName(1);
Integer name1 = gc2.getName();
System.out.println(name1);
//建立GenericClass物件,泛型使用String型別
GenericClass<String> gc3 = new GenericClass<>();
gc3.setName("小明");
String name2 = gc3.getName();
System.out.println(name2);
}
}
複製程式碼
2.定義和使用含有泛型的方法
泛型定義在方法的修飾符和返回值型別之間
格式: 修飾符 <泛型> 返回值型別 方法名(泛型 引數名){ 方法體; } 含有泛型的方法,在呼叫方法的時候確定泛型的資料型別 傳遞什麼型別的引數,泛型就是什麼型別
public class GenericMethod {
//定義一個含有泛型的方法
public <M> void method01(M m) {
System.out.println(m);
}
//定義一個含有泛型的靜態方法
public static <S> void method02(S s){
System.out.println(s);
}
//返回值泛型
public <T> T method03(T t) {
return t;
}
}
複製程式碼
使用該類
public class DemoGenericMethod {
public static void main(String[] args) {
//建立GenericMethod物件
GenericMethod gm = new GenericMethod();
/*
呼叫含有泛型的方法method01
傳遞什麼型別,泛型就是什麼型別
*/
gm.method01(10);
gm.method01("abc");
gm.method01(8.8);
gm.method01(true);
//靜態方法,通過類名.方法名(引數)可以直接使用
GenericMethod.method02("靜態方法");
GenericMethod.method02(1);
///泛型返回值
String s = gm.method03("aaa");
System.out.println(s);
}
}
複製程式碼
3.定義和使用含有泛型的介面
/**
* 定義含有泛型的介面
*/
public interface GenericInterface<I> {
public abstract void method(I i);
}
複製程式碼
含有泛型的介面第一種使用方式:定義介面的實現類,實現介面,指定介面的泛型
public class GenericInterfaceImpl1 implements GenericInterface<String> {
@Override
public void method(String s) {
System.out.println(s);
}
}
複製程式碼
public class DemoGenericInterface {
public static void main(String[] args) {
//建立GenericInterfaceImpl1物件
GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
gi1.method("字串");
}
}
複製程式碼
含有泛型的介面第二種使用方式:介面使用什麼泛型,實現類就使用什麼泛型,類跟著介面走
/**
* 含有泛型的介面第二種使用方式:介面使用什麼泛型,實現類就使用什麼泛型,類跟著介面走
* 就相當於定義了一個含有泛型的類,建立物件的時候確定泛型的型別
* public interface List<E>{
* boolean add(E e);
* E get(int index);
* }
* public class ArrayList<E> implements List<E>{
* public boolean add(E e) {}
* public E get(int index) {}
* }
*/
public class GenericInterfaceImpl2<I> implements GenericInterface<I>{
@Override
public void method(I i) {
System.out.println(i);
}
}
複製程式碼
public class DemoGenericInterface {
public static void main(String[] args) {
//建立GenericInterfaceImpl2物件
GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
gi2.method(10);
GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();
gi3.method(8.8);
}
}
複製程式碼
四、泛型萬用字元
1.泛型萬用字元的使用
當使用泛型類或者介面時,傳遞的資料中,泛型不確定,可以通過萬用字元 < ? > 表示。但是一旦使用泛型萬用字元後,只能使用Object類中的共性方法,集合中元素自身的方法無法使用。
泛型的萬用字元: ?:代表任意的資料型別 使用方式: 1.不能建立物件使用 2.只能作為方法的引數使用
/**
* 泛型的萬用字元:
* ?:代表任意的資料型別
* 使用方式:
* 不能建立物件使用
* 只能作為方法的引數使用
*/
public class DemoGeneric {
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集合使用什麼資料型別,可以泛型的萬用字元?來接收資料型別
* 注意:
* 泛型沒有繼承概念的
* @param list
*/
public static void printArray(ArrayList<?> list) {
Iterator<?> it = list.iterator();
while (it.hasNext()) {
//it.next()方法,取出的元素是Object,可以接收任意的資料型別
Object o = it.next();
System.out.println(o);
}
}
}
複製程式碼
2.泛型萬用字元的高階使用----受限泛型
之前設定泛型的時候,實際上可以是任意設定的,只要是類就可以設定。但是在Java中泛型可以指定一個泛型的上限和下限。
泛型的上限
- 格式:型別名稱 <? extends 類 > 物件名稱
- 意義:只接收該型別及其子類
泛型的下限
- 格式:型別名稱 <? super 類 > 物件名稱
- 意義:只接收該型別及其父類
/*
泛型的上限限定: ? extends E 代表使用的泛型只能是E型別的子類/本身
泛型的下限限定: ? super E 代表使用的泛型只能是E型別的父類/本身
*/
public class Demo06Generic {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement1(list1);
//getElement1(list2);//報錯
getElement1(list3);
//getElement1(list4);//報錯
//getElement2(list1);//報錯
//getElement2(list2);//報錯
getElement2(list3);
getElement2(list4);
/*
類與類之間的繼承關係
Integer extends Number extends Object
String extends Object
*/
}
// 泛型的上限:此時的泛型?,必須是Number型別或者Number型別的子類
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此時的泛型?,必須是Number型別或者Number型別的父類
public static void getElement2(Collection<? super Number> coll){}
}
複製程式碼
以上是我的整理,希望能幫助大家,謝謝。
作者:前程有光
連結:https://juejin.cn/post/6932061799520927758