深入淺出理解Java泛型的使用
一、泛型的意義




二、泛型的使用
1.jdk 5.0新增特性
2.在集合中使用泛型:
總結(jié):
A.集合接口或集合類在jdk5.0時(shí)都修改為帶泛型的結(jié)構(gòu)。
B.在實(shí)例化集合類時(shí),可以指明具體的泛型類型。
C.指明完以后,在集合類或接口中凡是定義類或接口時(shí),內(nèi)部結(jié)構(gòu)(比如:方法、構(gòu)造器、屬性等)使用類的泛型的位置,
都指定為實(shí)例化的泛型類型。比如:add(E e) --->實(shí)例化以后:add(Integer e)
D.注意點(diǎn):泛型的類型必須是類,不能是基本數(shù)據(jù)類型。需要用到基本數(shù)據(jù)類型的位置,用包裝類去替換
E.如果實(shí)例化時(shí),沒有指明泛型的類型。默認(rèn)類型為java.lang.Object類型。
3.如何自定義泛型結(jié)構(gòu):泛型類、泛型結(jié)構(gòu)、泛型方法
//在集合中使用泛型之前的情況:
@Test
public void test1(){
ArrayList list = new ArrayList();
//需求:存放學(xué)生的成績(jī)
list.add(78);
list.add(76);
list.add(89);
list.add(88);
//問題一:類型不安全
list.add("Tom");
for(Object score : list){
//問題二:強(qiáng)轉(zhuǎn)時(shí),可能出現(xiàn)ClassCateException
int stuScore = (Integer)score;
System.out.println(stuScore);
}
}
//在集合中使用泛型的情況:
@Test
public void test2(){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(78);
list.add(76);
list.add(89);
list.add(88);
//編譯時(shí),就會(huì)進(jìn)行類型檢查,保證數(shù)據(jù)的安全
// list.add("Tom");
//方式一:
for(Integer score : list){
//避免了強(qiáng)轉(zhuǎn)操作
int stuScore = score;
System.out.println(stuScore);
}
//方式二:
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
int stuScore = iterator.next();
System.out.println(stuScore);
}
}
//在集合中使用泛型的情況:以HashMap為例
@Test
public void test3(){
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom",87);
map.put("Jerry",87);
map.put("Jack",67);
//泛型的嵌套
Set<Map.Entry<String, Integer>> entry = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
while(iterator.hasNext()){
Map.Entry<String, Integer> entry1 = iterator.next();
String key = entry1.getKey();
Integer value = entry1.getValue();
System.out.println(key + "----" + value);
}
}
三、自定義泛型類
1.泛型類可能有多個(gè)參數(shù),此時(shí)應(yīng)將多個(gè)參數(shù)一起放在尖括號(hào)內(nèi)。比如:
<E1,E2,E3>
2.泛型類的構(gòu)造器如下: public GenericClass (){}。
而下面是錯(cuò)誤的: public GenericClass < E >(){}
3.實(shí)例化后,操作原來泛型付置的結(jié)構(gòu)必須與指定的泛型類型致。
4.泛型不同的引用不能相互賦值。
盡管在編譯時(shí) ArrayList < String >和 ArrayListslnteger 是兩種類型,但是,在運(yùn)行時(shí)只有一個(gè) ArrayList 被加載到 JVM 中。
5.泛型如果不指定,將被探除,泛型對(duì)應(yīng)的類型昀按照 Object 處理,但不等價(jià)于Object 。經(jīng)驗(yàn):泛型要使用路都用。要不用,一路都本要用。
6.如果泛型類是一個(gè)按口或抽象類,則不可創(chuàng)建泛型類的對(duì)象。
7.jdk1.7 ,泛的簡(jiǎn)化操作 ArrayList < Fruit > flist = new ArrayList<>();
8.泛型的指定中不能使用基本數(shù)據(jù)類型,可以使用包裝類替換。
1.關(guān)于自定義泛型類、泛型接口:
@Test
public void test1(){
//如果定義了泛型類,實(shí)例化沒有指明類的泛型,則認(rèn)為此泛型類型為Object類型
//要求:如果大家定義了類是帶泛型的,建議在實(shí)例化時(shí)要指明類的泛型。
Order order = new Order();
order.setOrderT(123);
order.setOrderT("ABC");
//建議:實(shí)例化時(shí)指明類的泛型
Order<String> order1 = new Order<String>("OrderAA", 1001, "Order:AA");
order1.setOrderT("AA:hello");
}
@Test
public void test2(){
SubOrder sub1 = new SubOrder();
//由于子類在繼承帶泛型的父類時(shí),指明了泛型類型。則實(shí)例化子類對(duì)象時(shí),不再需要指明泛型。
sub1.setOrderT(1122);
SubOrder1<String> sub2 = new SubOrder1<>();
sub2.setOrderT("order2...");
}
//測(cè)試泛型方法
@Test
public void test3(){
Order<String> order = new Order<>();
Integer[] arr = new Integer[]{1, 2, 3, 4};
//泛型方法在調(diào)用時(shí),指明泛型參數(shù)的類型
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);//[1, 2, 3, 4]
}
自定義泛型類
public class Order<T> {
String orderName;
int orderId;
//類的內(nèi)部結(jié)構(gòu)就可以使用類的泛型
T orderT;
public Order(){};
public Order(String orderName,int orderId,T orderT){
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
public T getOrderT(){
return orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
public void setOrderT(T orderT){
this.orderT = orderT;
}
//泛型方法:在方法中出現(xiàn)了泛型的結(jié)構(gòu),翻新參數(shù)與類的泛型參數(shù)沒有任何關(guān)系。
//換句話說,泛型方法所屬的類是不是泛型類都沒有關(guān)系。
//泛型方法,可以聲明為靜態(tài)的,原因:泛型參數(shù)是在調(diào)用方法時(shí)確定的,并非在實(shí)例化時(shí)確定。
public <E> List<E> copyFromArrayToList(E[] arr){
ArrayList<E> list = new ArrayList<>();
for(E e : arr){
list.add(e);
}
return list;
}
}
2.泛型在繼承方面的體現(xiàn)
1.泛型在繼承方面的體現(xiàn)
雖然類A是類B的父類,但是G<A>,和<B>二者不具備子父類關(guān)系,二者是并列關(guān)系。
補(bǔ)充:類A是類B的父類,A<G>是B<G>的父類
public void test1(){
Object obj = null;
String str = null;
obj = str;//子類對(duì)象賦值給父類;多態(tài)的體現(xiàn)
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;//子類對(duì)象賦值給父類;多態(tài)的體現(xiàn)
//編譯不通過
// Date date = new Date();
// str = date;
List<Object> list1 = null;
List<String> list2 = null;
//此時(shí)的list1和list2的類型不具有子父類的關(guān)系
//編譯不通過
// list1 = list2;
}
@Test
public void test2(){
AbstractList<String> list1 = null;
List<String> list2 = null;
ArrayList<String> list3 = null;
list1 = list3;
list2 = list3;
List<String> list4 = new ArrayList<>();
}

3.通配符的使用
@<?>
允許所有泛型的引用調(diào)用
@通配符指定上限
上限 extends :使用時(shí)指定的類型必須是繼承某個(gè)類,或者實(shí)現(xiàn)某個(gè)接口,即<=
@通配符指定下限
下限 super :使用時(shí)指定的類型不能小于操作的類,即>=
@舉例:
><? extends Number >(無窮小, Number ]
只允許泛型為 Number 及 Number 子類的引用調(diào)用
><? super Number > INumber ,無窮大)
只允許泛型為 Number 及 Number 父類的引用調(diào)用
><? extends Comparable >
只允許泛型為實(shí)現(xiàn) ComDarable 接口的實(shí)現(xiàn)類的引用調(diào)用

/*
2.通配符的使用
通配符:?
類A是類B的父類,G<A>和G<B>是沒有關(guān)系的,二者共同的父類是:G<?>
*/
@Test
public void test3(){
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list1;
list = list2;
//編譯通過
// print(list1);
// print(list2);
ArrayList<String> list3 = new ArrayList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
list = list3;
//添加(寫入):對(duì)于List<?>就不能向其內(nèi)部添加數(shù)據(jù)。
//除了添加null之外。
// list.add("dd");
// list.add('d');
list.add(null);
//獲取(讀取):允許讀取數(shù)據(jù),讀取的數(shù)據(jù)類型為Object
Object o = list.get(0);
System.out.println(o);
}
public void print(List<?> list){
Iterator<?> iterator = list.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
}
/*
3.有限制條件的通配符的使用。
? extends A:
G<? extends A> 可以作為G<A>和G<B>的父類,其中B是A的子類
? super A:
G<? super A> 可以作為G<A>和G<B>的父類,其中B是A的父類
*/
@Test
public void test4(){
List<? extends Person> list1 = null;//extends可理解為:小于等于
List<? super Person> list2 = null;//super可以理解為:大于等于
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
list1 = list3;
list1 = list4;
// list1 = list5;//編譯報(bào)錯(cuò)
// list2 = list3;//編譯報(bào)錯(cuò)
list2 = list4;
list2 = list5;
//讀取數(shù)據(jù):
list1 = list3;
Person p = list1.get(0);
//編譯不通過:
// Student s = list1.get(0);
list2 = list4;
Object obj = list2.get(0);
//編譯不通過
// Person obj = list2.get(0);
//寫入數(shù)據(jù):
//編譯不通過
// list1.add(new Student());
//編譯通過
list2.add(new Person());
list2.add(new Student());
}

到此這篇關(guān)于深入淺出理解Java泛型的使用的文章就介紹到這了,更多相關(guān)Java泛型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis3使用@Select等注解實(shí)現(xiàn)增刪改查操作
這篇文章主要介紹了mybatis3使用@Select等注解實(shí)現(xiàn)增刪改查操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11
springboot根據(jù)實(shí)體類生成表的實(shí)現(xiàn)方法
本文介紹了如何通過SpringBoot工程引入SpringDataJPA,并通過實(shí)體類自動(dòng)生成數(shù)據(jù)庫(kù)表的過程,包括常見問題解決方法,感興趣的可以了解一下2024-09-09
Springboot實(shí)現(xiàn)添加本地模塊依賴方式
這篇文章主要介紹了Springboot實(shí)現(xiàn)添加本地模塊依賴方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
Gateway網(wǎng)關(guān)自定義攔截器的不可重復(fù)讀取數(shù)據(jù)問題
這篇文章主要介紹了Gateway網(wǎng)關(guān)自定義攔截器的不可重復(fù)讀取數(shù)據(jù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
mybatis自動(dòng)生成時(shí)如何設(shè)置不生成Example類詳解
這篇文章主要給大家介紹了關(guān)于mybatis自動(dòng)生成時(shí)如何設(shè)置不生成Example類的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-05-05

