最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Java十四篇:泛型

2023-03-03 00:03 作者:小劉Java之路  | 我要投稿

泛型是一種“代碼模板”,可以用一套代碼套用各種類型。


反方向的鐘


什么是泛型

在講解什么是泛型之前,我們先觀察Java標(biāo)準(zhǔn)庫(kù)提供的ArrayList,它可以看作“可變長(zhǎng)度”的數(shù)組,因?yàn)橛闷饋?lái)比數(shù)組更方便。

實(shí)際上ArrayList內(nèi)部就是一個(gè)Object[]數(shù)組,配合存儲(chǔ)一個(gè)當(dāng)前分配的長(zhǎng)度,就可以充當(dāng)“可變數(shù)組”:

publicclass ArrayList {
? ?private Object[] array;
? ?privateint size;
? ?public void add(Object e) {...}
? ?public void remove(int index) {...}
? ?public Object get(int index) {...}
}

如果用上述ArrayList存儲(chǔ)String類型,會(huì)有這么幾個(gè)缺點(diǎn):

  • 需要強(qiáng)制轉(zhuǎn)型;

  • 不方便,易出錯(cuò)。

例如,代碼必須這么寫(xiě):

ArrayList list = new ArrayList();
list.add("Hello");
// 獲取到Object,必須強(qiáng)制轉(zhuǎn)型為String:
String first = (String) list.get(0);

很容易出現(xiàn)ClassCastException,因?yàn)槿菀住罢`轉(zhuǎn)型”:

list.add(new Integer(123));
// ERROR: ClassCastException:
String second = (String) list.get(1);

要解決上述問(wèn)題,我們可以為String單獨(dú)編寫(xiě)一種ArrayList

publicclass StringArrayList {
? ?private String[] array;
? ?privateint size;
? ?public void add(String e) {...}
? ?public void remove(int index) {...}
? ?public String get(int index) {...}
}

這樣一來(lái),存入的必須是String,取出的也一定是String,不需要強(qiáng)制轉(zhuǎn)型,因?yàn)榫幾g器會(huì)強(qiáng)制檢查放入的類型:

StringArrayList list = new StringArrayList();
list.add("Hello");
String first = list.get(0);
// 編譯錯(cuò)誤: 不允許放入非String類型:
list.add(new Integer(123));

問(wèn)題暫時(shí)解決。

然而,新的問(wèn)題是,如果要存儲(chǔ)Integer,還需要為Integer單獨(dú)編寫(xiě)一種ArrayList

publicclass IntegerArrayList {
? ?private Integer[] array;
? ?privateint size;
? ?public void add(Integer e) {...}
? ?public void remove(int index) {...}
? ?public Integer get(int index) {...}
}

實(shí)際上,還需要為其他所有class單獨(dú)編寫(xiě)一種ArrayList

  • LongArrayList

  • DoubleArrayList

  • PersonArrayList

  • ...

這是不可能的,JDK的class就有上千個(gè),而且它還不知道其他人編寫(xiě)的class。

為了解決新的問(wèn)題,我們必須把ArrayList變成一種模板:ArrayList<T>,代碼如下:

publicclass ArrayList<T> {
? ?private T[] array;
? ?privateint size;
? ?public void add(T e) {...}
? ?public void remove(int index) {...}
? ?public T get(int index) {...}
}

T可以是任何class。這樣一來(lái),我們就實(shí)現(xiàn)了:編寫(xiě)一次模版,可以創(chuàng)建任意類型的ArrayList

// 創(chuàng)建可以存儲(chǔ)String的ArrayList:
ArrayList<String> strList = new ArrayList<String>();
// 創(chuàng)建可以存儲(chǔ)Float的ArrayList:
ArrayList<Float> floatList = new ArrayList<Float>();
// 創(chuàng)建可以存儲(chǔ)Person的ArrayList:
ArrayList<Person> personList = new ArrayList<Person>();

因此,泛型就是定義一種模板,例如ArrayList<T>,然后在代碼中為用到的類創(chuàng)建對(duì)應(yīng)的ArrayList<類型>

ArrayList<String> strList = new ArrayList<String>();

由編譯器針對(duì)類型作檢查:

strList.add("hello"); // OK
String s = strList.get(0); // OK
strList.add(new Integer(123)); // compile error!
Integer n = strList.get(0); // compile error!

這樣一來(lái),既實(shí)現(xiàn)了編寫(xiě)一次,萬(wàn)能匹配,又通過(guò)編譯器保證了類型安全:這就是泛型。

向上轉(zhuǎn)型

在Java標(biāo)準(zhǔn)庫(kù)中的ArrayList<T>實(shí)現(xiàn)了List<T>接口,它可以向上轉(zhuǎn)型為List<T>

publicclass ArrayList<T> implements List<T> {
? ?...
}

List<String> list = new ArrayList<String>();

即類型ArrayList<T>可以向上轉(zhuǎn)型為List<T>。

要特別注意:不能把ArrayList<Integer>向上轉(zhuǎn)型為ArrayList<Number>List<Number>。

這是為什么呢?假設(shè)ArrayList<Integer>可以向上轉(zhuǎn)型為ArrayList<Number>,觀察一下代碼:

// 創(chuàng)建ArrayList<Integer>類型:
ArrayList<Integer> integerList = new ArrayList<Integer>();
// 添加一個(gè)Integer:
integerList.add(new Integer(123));
// “向上轉(zhuǎn)型”為ArrayList<Number>:
ArrayList<Number> numberList = integerList;
// 添加一個(gè)Float,因?yàn)镕loat也是Number:
numberList.add(new Float(12.34));
// 從ArrayList<Integer>獲取索引為1的元素(即添加的Float):
Integer n = integerList.get(1); // ClassCastException!

我們把一個(gè)ArrayList<Integer>轉(zhuǎn)型為ArrayList<Number>類型后,這個(gè)ArrayList<Number>就可以接受Float類型,因?yàn)?code>Float是Number的子類。但是,ArrayList<Number>實(shí)際上和ArrayList<Integer>是同一個(gè)對(duì)象,也就是ArrayList<Integer>類型,它不可能接受Float類型, 所以在獲取Integer的時(shí)候?qū)a(chǎn)生ClassCastException。

實(shí)際上,編譯器為了避免這種錯(cuò)誤,根本就不允許把ArrayList<Integer>轉(zhuǎn)型為ArrayList<Number>

ArrayList和ArrayList兩者完全沒(méi)有繼承關(guān)系。

使用泛型

使用泛型時(shí),把泛型參數(shù)<T>替換為需要的class類型,例如:ArrayList<String>ArrayList<Number>等;

可以省略編譯器能自動(dòng)推斷出的類型,例如:List<String> list = new ArrayList<>();

不指定泛型參數(shù)類型時(shí),編譯器會(huì)給出警告,且只能將<T>視為Object類型;

可以在接口中定義泛型類型,實(shí)現(xiàn)此接口的類必須實(shí)現(xiàn)正確的泛型類型。

編寫(xiě)泛型

編寫(xiě)泛型類比普通類要復(fù)雜。通常來(lái)說(shuō),泛型類一般用在集合類中,例如ArrayList<T>,我們很少需要編寫(xiě)泛型類。

如果我們確實(shí)需要編寫(xiě)一個(gè)泛型類,那么,應(yīng)該如何編寫(xiě)它?

可以按照以下步驟來(lái)編寫(xiě)一個(gè)泛型類。

首先,按照某種類型,例如:String,來(lái)編寫(xiě)類:

publicclass Pair {
? ?private String first;
? ?private String last;
? ?public Pair(String first, String last) {
? ? ? ?this.first = first;
? ? ? ?this.last = last;
? ?}
? ?public String getFirst() {
? ? ? ?return first;
? ?}
? ?public String getLast() {
? ? ? ?return last;
? ?}
}

然后,標(biāo)記所有的特定類型,這里是String

publicclass Pair {
? ?private String first;
? ?private String last;
? ?public Pair(String first, String last) {
? ? ? ?this.first = first;
? ? ? ?this.last = last;
? ?}
? ?public String getFirst() {
? ? ? ?return first;
? ?}
? ?public String getLast() {
? ? ? ?return last;
? ?}
}

最后,把特定類型String替換為T,并申明<T>

publicclass Pair<T> {
? ?private T first;
? ?private T last;
? ?public Pair(T first, T last) {
? ? ? ?this.first = first;
? ? ? ?this.last = last;
? ?}
? ?public T getFirst() {
? ? ? ?return first;
? ?}
? ?public T getLast() {
? ? ? ?return last;
? ?}
}

熟練后即可直接從T開(kāi)始編寫(xiě)。

靜態(tài)方法

編寫(xiě)泛型類時(shí),要特別注意,泛型類型<T>不能用于靜態(tài)方法。

多個(gè)泛型類型

泛型可以同時(shí)定義多種類型,例如Map<K, V>。

擦拭法

Java的泛型是采用擦拭法實(shí)現(xiàn)的;

擦拭法決定了泛型<T>

  • 不能是基本類型,例如:int

  • 不能獲取帶泛型類型的Class,例如:Pair<String>.class;

  • 不能判斷帶泛型類型的類型,例如:x instanceof Pair<String>;

  • 不能實(shí)例化T類型,例如:new T()。

泛型方法要防止重復(fù)定義方法,例如:public boolean equals(T obj)

子類可以獲取父類的泛型類型<T>。

通配符

使用類似<? extends Number>通配符作為方法參數(shù)時(shí)表示:

  • 方法內(nèi)部可以調(diào)用獲取Number引用的方法,例如:Number n = obj.getFirst();

  • 方法內(nèi)部無(wú)法調(diào)用傳入Number引用的方法(null除外),例如:obj.setFirst(Number n);。

即一句話總結(jié):使用extends通配符表示可以讀,不能寫(xiě)。

使用類似<T extends Number>定義泛型類時(shí)表示:

  • 泛型類型限定為Number以及Number的子類。

super

使用類似<? super Integer>通配符作為方法參數(shù)時(shí)表示:

  • 方法內(nèi)部可以調(diào)用傳入Integer引用的方法,例如:obj.setFirst(Integer n);;

  • 方法內(nèi)部無(wú)法調(diào)用獲取Integer引用的方法(Object除外),例如:Integer n = obj.getFirst();。

即使用super通配符表示只能寫(xiě)不能讀。

使用extendssuper通配符要遵循PECS原則。

無(wú)限定通配符<?>很少使用,可以用<T>替換,同時(shí)它是所有<T>類型的超類。

泛型和反射

Java的部分反射API也是泛型、例如:Class<T>就是泛型:Constructor<T>

可以聲明帶泛型的數(shù)組,但不能直接創(chuàng)建帶泛型的數(shù)組,必須強(qiáng)制轉(zhuǎn)型;

可以通過(guò)Array.newInstance(Class<T>, int)創(chuàng)建T[]數(shù)組,需要強(qiáng)制轉(zhuǎn)型;

同時(shí)使用泛型和可變參數(shù)時(shí)需要特別小心。


結(jié)尾

下一章我們來(lái)講講‘反射’,他在Java中的應(yīng)用是非常廣泛的,學(xué)會(huì)了你會(huì)又掌握了一項(xiàng)技巧。


總結(jié):

1.集合中也大量了應(yīng)用的范,來(lái)簡(jiǎn)化代碼,讓代碼更加的健壯。

2.范型有的時(shí)候就是一個(gè)模板,你按照他的方式去實(shí)現(xiàn),就可以完成你的需求和功能

3.在反射中.class也是應(yīng)用到了反射,去獲取私有類中的對(duì)象和屬性

4.范型使得代碼更加的簡(jiǎn)潔和規(guī)范了

5.范型可以向上轉(zhuǎn)型,向他的父類直接定義




Java十四篇:泛型的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
泰和县| 黎川县| 搜索| 怀远县| 剑河县| 汕尾市| 洞口县| 寿宁县| 包头市| 海原县| 绥江县| 宜阳县| 额尔古纳市| 阿克| 屯昌县| 姚安县| 中江县| 建湖县| 奇台县| 安阳市| 温泉县| 天祝| 介休市| 新化县| 左权县| 南丹县| 黄骅市| 石首市| 西吉县| 崇左市| 台东市| 贵溪市| 宜宾县| 板桥市| 汪清县| 汉川市| 泸水县| 任丘市| 深水埗区| 衢州市| 明溪县|