本部分主要介紹:Java 的泛型、泛型通配符使用的規(guī)則和注意事項(xiàng)
泛型總結(jié)
- 泛型是 JDK 1.5 出現(xiàn)的技術(shù)道川,是為了 Java 安全性考慮累铅。泛型即限定類型的使用,將運(yùn)行時(shí)異常提前到編譯時(shí)異常蚤吹。
- 泛型可以在定義類、方法和接口上
- 類中泛型不能創(chuàng)建對(duì)象
T t = new T()
随抠,因?yàn)榉盒褪遣淮_定的類型裁着,即無(wú)法開(kāi)辟空間 - 接口的泛型不能是成員變量。接口的成員變量的修飾符
public static final
與泛型的使用規(guī)則相違背(即不確定類型拱她,如何成為靜態(tài)常量二驰,為實(shí)現(xiàn)類提供規(guī)則呢!) - 定義泛型可以不使用椭懊,不使用時(shí)默認(rèn)是
Obejct
類型
- 類中泛型不能創(chuàng)建對(duì)象
- 泛型通配符 只適用于方法定義時(shí)的 方法的形參 (不是調(diào)用方法的傳入的實(shí)參)以復(fù)用代碼為目的
泛型出現(xiàn)的目的
-
泛型的本質(zhì)
- 類型參數(shù)化诸蚕,將類型當(dāng)作參數(shù)步势。
- 在定義類或集合(當(dāng)然集合是 Java 自帶的)時(shí)氧猬,不指定元素的明確類型,直到創(chuàng)建對(duì)象或集合時(shí)坏瘩,才明確對(duì)象或集合中的元素類型盅抚。
-
泛型的好處
限定類型,避免類型轉(zhuǎn)換錯(cuò)誤
可以把異常從運(yùn)行時(shí)期提到編譯時(shí)期
-
與集合連用倔矾,不需要轉(zhuǎn)換類型
ArrayList<String> list = new ArrayList<String>(); // 泛型完整的寫法 // ArrayList<String> list = new ArrayList(); // 泛型的簡(jiǎn)化寫法 list.add("ab.c"); list.get(0).split("\\."); // 可以直接調(diào)用 String 方法妄均,不需要轉(zhuǎn)換
-
泛型與
Object
相比,限定類型的使用集合在明確泛型類型時(shí)哪自,默認(rèn)使用的是
Object
類型丰包,即可以接受 Java 的所有類型。-
在 Java 中
Object
類是所有類的父類壤巷,Object
可以接受所有類型(8 中基本類型除外)邑彪。當(dāng)向集合添加元素時(shí) 向上轉(zhuǎn)型 為Object
類型,當(dāng)取出元素時(shí) 向下轉(zhuǎn)型胧华,如下寄症,編譯器并不會(huì)報(bào)錯(cuò),只有在運(yùn)行時(shí)矩动,才會(huì)報(bào)CalssCastExecption
異常有巧。ArrayList list = new ArrayList(); // 沒(méi)有指定泛型,實(shí)際默認(rèn)是以 Object 類型接受 list.add(1); // 編譯不會(huì)報(bào)錯(cuò) list.add("abc"); // 編譯不會(huì)報(bào)錯(cuò) // 當(dāng)取出集合元素時(shí)悲没,編譯并不會(huì)報(bào)錯(cuò)篮迎;運(yùn)行時(shí)報(bào)錯(cuò) String str = (String) list.get(0); String in = (String) list.get(1);
-
而泛型就是將類型做限定(只有在類型限定范圍能,才可以使用),將錯(cuò)誤提示發(fā)生在編譯時(shí)期(這也是 Java 一直在做的甜橱,將運(yùn)行時(shí)期錯(cuò)誤享言,提到編譯時(shí)期)。如下渗鬼,泛型限定
String
览露,向其添加Integer
編譯時(shí)期就會(huì)報(bào)錯(cuò)。ArrayList<String> list = new ArrayList<String>(); list.add(1); //編譯時(shí)期譬胎,直接提示錯(cuò)誤差牛,這樣對(duì)集合就做了類型的限定
泛型的注意事項(xiàng)
-
泛型格式
數(shù)據(jù)類型<泛型的類型> 對(duì)象 = new 數(shù)據(jù)類型<泛型的類型>();
-
泛型一般與集合連用較多,正常書寫方法(等號(hào)兩邊的泛型如果寫堰乔,就必須保持一致)
ArrayList<String> list = new ArrayList<String>();
-
簡(jiǎn)化寫法(jdk 1.7 出現(xiàn)的特性偏化,依據(jù)右側(cè)推測(cè)左側(cè)的類型)
ArrayList<String> list = new ArrayList();
-
介紹泛型以下幾種寫法(與集合連用)
-
泛型推斷,等號(hào)左邊寫泛型镐侯,右邊可以不寫泛型侦讨。等號(hào)左邊是完整的泛型定義,可以從左邊推斷出右邊的泛型類型苟翻,集合只能添加
String
類型ArrayList<String> list = new ArrayList<>(); list.add("abc"); //正確 list.add(new Integer(1)); // 錯(cuò)誤
-
等號(hào)右邊寫泛型韵卤,左邊不寫。這樣就如同沒(méi)有泛型崇猫,任何類型都可以添加沈条。
ArrayList list = new ArrayList<String>(); list.add("abc"); // 正確 list.add(new Integer(1)); // 正確
-
-
通配符注意
- 泛型通配符 不適用 于集合對(duì)象的創(chuàng)建
- 泛型通配符 適用 于方法的形參上
泛型類、方法诅炉、接口
-
泛型類
-
泛型類定義
public class GenericType<T> { // <T> 就是形參 //也可以定義多個(gè)泛型 <T, E> T t; }
類中的泛型蜡歹,不能創(chuàng)建對(duì)象
T t = new T()
√樯眨可以這樣理解:泛型是參數(shù)化類型月而,類中的泛型就是參數(shù),在沒(méi)有明確實(shí)參的情況议纯,泛型怎么可以創(chuàng)建對(duì)象呢父款!。實(shí)例化對(duì)象時(shí)痹扇,在沒(méi)有明確泛型類型時(shí)铛漓,泛型類型默認(rèn)為
Object
-
-
泛型接口
-
泛型接口定義
public interface GenericInter<T, E> { // <T> 就是形參 //也可以定義多個(gè)泛型 <T, E> //T t; // 錯(cuò)誤 public abstract void method1(T t); public abstract void method2(E e); }
泛型接口不可以定義成員變量
T t;
■旯梗可以這樣理解:接口的成員都是public static final
修飾的浓恶,這是接口的特性(提供規(guī)則,子類必須遵循结笨,不可以更改)包晰。泛型接口湿镀,泛型沒(méi)有明確類型時(shí),就不能向子類提供規(guī)則伐憾。相反勉痴,則違背了接口的規(guī)則。-
泛型接口树肃,只會(huì)體現(xiàn)在接口的方法中
public abstract void method(T t);
-
實(shí)現(xiàn)接口的 3 中方式
-
實(shí)現(xiàn)接口時(shí)蒸矛,無(wú)泛型,默認(rèn)使用
Object
類型public class GenericType implements GenericInter { @Override public void method1(Object t) { } @Override public void method2(Object e) { } }
-
實(shí)現(xiàn)接口時(shí)胸嘴,實(shí)現(xiàn)類使用泛型雏掠,但未明確泛型類型時(shí),實(shí)現(xiàn)類與接口的泛型必須保持一致(此類稱之為泛型類)
public class GenericType<T, E> implements GenericInter<T, E> { @Override public void method1(E t) { } @Override public void method2(T e) { } }
-
實(shí)現(xiàn)接口時(shí)劣像,就明確類型
public class GenericType implements GenericInter<String, Integer> { @Override public void method1(Integer t) { } @Override public void method2(String e) { } }
-
-
-
泛型方法
-
泛型方法定義乡话,泛型定義在方法的返回類型前面
class GenericMethod { public <T> void method(T t) { } }
-
泛型方法使用
GenericMethod g = new GenericMethod(); g.method("abc"); // 調(diào)用方法時(shí),傳入泛型確定類型
-
泛型通配符
-
通配符的種類
-
?
任意類型耳奕,沒(méi)有明確那就是Object
以及任意的 Java 類型 -
? extends E
向下限定绑青,E 及其子類 -
? super E
向上限定,E 及其父類
-
-
通配符使用場(chǎng)景
-
通配符的使用場(chǎng)景是方法的 形參上 屋群,表示方法可以接受的數(shù)據(jù)類型
public void method(ArrayList<? extends People> list) { }
-
泛型通配符不是用在對(duì)象定義上
-
如集合
// 語(yǔ)法報(bào)錯(cuò) ArrayList<?> list = new ArrayList<?>(); ArrayList<? extends People> list = new ArrayList<? entends People>(); ArrayList<? super Student> list = new ArrayList<? super Student>(); // 任何元素都添加不上闸婴,除了 null ArrayList<?> list = new ArrayList<>(); // 任何元素都添加不上,除了 null ArrayList<? extends People> list = new ArrayList<>(); // 可以添加 Student以及子類 ArrayList<? super Student> list = new ArrayList<>();
在類上使用谓晌、在接口上使用掠拳、在調(diào)用方法時(shí)癞揉,都會(huì)發(fā)生語(yǔ)法錯(cuò)誤
-
-
-
通配符出現(xiàn)的原因
數(shù)組有協(xié)變纸肉,集合沒(méi)有協(xié)變
-
協(xié)變
Student extends People
,那么Peole[]
兼容Studnet[]
喊熟。集合使用泛型之后是不能協(xié)變柏肪,
ArrayList<People>
不是ArrayList<Student>
父類,當(dāng)然也不可以兼容的-
集合想要兼容芥牌,通配符解決了這個(gè)問(wèn)題烦味。
Student
和People
都可以當(dāng)此方法的實(shí)參public void method(ArrayList<? extends People> list) { }
-
問(wèn)題的提出
定義 兩個(gè)類,
Student
類繼承People
類-
定義兩個(gè)數(shù)組和兩個(gè)集合
Student[] stu = new Studnet[2]; People[] p = new Peoplep[2]; ArrayList<People> list = new ArrayList<People>(); ArrayList<Student> list1 = new ArrayList<>();
-
定義兩個(gè)方法
public void method1(People[] people){ } public void method2(List<People> liat) { }
-
調(diào)用兩個(gè)方法
method1(p); method1(stu); // 類型兼容 method2(list); method2(list1); // 類型不兼容
-
解決辦法
-
通配符的出現(xiàn)
-
修改
method2
方法壁拉,表示People
及其子類都兼容public void method2(List<? extends People> liat) { }
-
-