摘要:使用表示泛型中的基本思想就是可以通過(guò)使用像這樣適當(dāng)?shù)某悂?lái)實(shí)現(xiàn)泛型類。請(qǐng)看例子使用實(shí)現(xiàn)泛型使用接口類型表示泛型當(dāng)有多個(gè)類要在一個(gè)通用的方法里表示泛型時(shí),來(lái)表示可能就顯得捉襟見(jiàn)肘了,因?yàn)檫@個(gè)時(shí)候無(wú)法明確的知道用戶到底需要拆箱為哪種類。
1.1 使用Object表示泛型
Java中的基本思想就是可以通過(guò)使用像Object這樣適當(dāng)?shù)某悂?lái)實(shí)現(xiàn)泛型類。--《數(shù)據(jù)結(jié)構(gòu)與算法分析 Java語(yǔ)言描述》
文中的超類也就是父類的意思。
使用Object這樣特殊的類來(lái)實(shí)現(xiàn)泛型是用到了Object是所有類的父類這個(gè)基本思想,但是這種實(shí)現(xiàn)方法帶來(lái)了兩個(gè)問(wèn)題:
1. 沒(méi)有覆蓋基本類型,因?yàn)榛绢愋筒皇且妙愋?,所以不能用類表示基本類型,因此Object不是基本類型的父類 2. 在使用泛型后的對(duì)象時(shí)需要強(qiáng)制轉(zhuǎn)換,如果強(qiáng)轉(zhuǎn)失敗了也不會(huì)在編譯時(shí)報(bào)錯(cuò),只會(huì)在運(yùn)行時(shí)報(bào)強(qiáng)轉(zhuǎn)失敗ClassCastException
這樣Object在實(shí)際使用中就不是一個(gè)非常完美的實(shí)現(xiàn)泛型的一個(gè)方法,但是提供了一個(gè)實(shí)現(xiàn)泛型的基本思想,就是通過(guò)父類來(lái)實(shí)現(xiàn)泛型。請(qǐng)看例子
/** * 使用Object實(shí)現(xiàn)泛型 */ public class ObjectGeneric { private Object storedValue; public Object read(){ return storedValue; } public void write(Object value){ storedValue = value; } public static void main(String[] args) { ObjectGeneric objectGeneric = new ObjectGeneric(); objectGeneric.write("23"); String val = (String)objectGeneric.read(); System.out.println(val); } }1.2 使用接口類型表示泛型
當(dāng)有多個(gè)類要在一個(gè)通用的方法里表示泛型時(shí),Object來(lái)表示可能就顯得捉襟見(jiàn)肘了,因?yàn)檫@個(gè)時(shí)候無(wú)法明確的知道用戶到底需要拆箱為哪種類。例如,String和Shape類的數(shù)組要用同一個(gè)findMax函數(shù)來(lái)找出最大的元素,這時(shí)在實(shí)現(xiàn)findMax的時(shí)候可能需要隨時(shí)要判斷入?yún)⒌念愋?,這對(duì)于泛型的意義(減少代碼量)來(lái)說(shuō)是毀滅性的。
因此這個(gè)時(shí)候需要找到String和Shape類的共同之處,抽象出一個(gè)接口,并在findMax里面用作入?yún)?lái)替代直接傳入String或Shape類。findMax的核心在于元素間的比較,在jdk中有一個(gè)接口java.lang.Comparable是滿足findMax需求的。
首先,定義一個(gè)實(shí)現(xiàn)了Comparable接口的抽象類Shape
public abstract class Shape implements Comparable{ protected Double area; @Override public int compareTo(Object o) { Shape shape = (Shape)o; return area.compareTo(shape.getArea()); } public Double getArea() { return area; } public void setArea(Double area) { this.area = area; } }
然后派生出兩個(gè)具體的Shape子類:Square,Circle
public class Square extends Shape{ public Square(double len){ area = len*len; } } public class Circle extends Shape{ public Circle(double radius){ area = radius*radius*3.14; } }
最后是findMax函數(shù)
import static com.google.common.base.Preconditions.checkArgument; public class InterfaceGeneric { public static void main(String[] args) { Shape[] sh = { new Circle(3.0), new Square(3.0) }; String[] str = { "John", "Benjamin", "Steve" }; Comparable[] comparables = { new Circle(3.0), "Benjamin" }; System.out.println(findMax(sh)); System.out.println(findMax(str)); System.out.println(findMax(comparables)); } public static Comparable findMax(Comparable[] arr){ checkArgument(arr.length>0); int max = 0; for(int i = 0 ;i0){ max = i; } } return arr[max]; } }
在findMax函數(shù)中,因?yàn)橐阎雲(yún)⑹菍?shí)現(xiàn)了Comparable接口的類,因此可以不用轉(zhuǎn)換直接使用compareTo函數(shù),這是利用了接口的特性來(lái)實(shí)現(xiàn)的泛型。
System.out.println(findMax(comparables))會(huì)拋出ClassCastException異常,這是因?yàn)樵赾ompareTo中拆箱時(shí)無(wú)法將String類強(qiáng)轉(zhuǎn)為Shape類導(dǎo)致的。
以上兩種方式都存在編譯不會(huì)報(bào)錯(cuò),但是會(huì)在運(yùn)行時(shí)報(bào)錯(cuò)的問(wèn)題,這樣就導(dǎo)致程序是不可控的,因?yàn)闊o(wú)法提前預(yù)知程序哪里會(huì)拋RuntimeException,所以需要一種泛型方法來(lái)強(qiáng)制使得異常能夠出現(xiàn)在編譯階段而不是運(yùn)行時(shí)。
在java5中引入了泛型類的概念,通過(guò)<>運(yùn)算符實(shí)現(xiàn)泛型。將第一個(gè)例子用<>運(yùn)算符實(shí)現(xiàn)如下:
public class DiamondGeneric{ private AnyType storedValue; public AnyType read(){ return storedValue; } public void write(AnyType value){ storedValue = value; } public static void main(String[] args) { DiamondGeneric val = new DiamondGeneric<>(); val.write("this is a test"); System.out.println(val.read()); } }
在這里DiamondGeneric
在這里還用到了Java7增加的一種新的語(yǔ)言特性,菱形運(yùn)算符:new DiamondGeneric<>(),在前面已經(jīng)指定AnyType為String,因此在后面不必再指定類型。
想一種復(fù)雜的狀況,如果一個(gè)接口的多態(tài)實(shí)現(xiàn)需要在一個(gè)通用方法做同樣的操作,例如,Shape接口有一個(gè)area方法,有一個(gè)實(shí)現(xiàn)Circle,一個(gè)實(shí)現(xiàn)Square,需要一個(gè)findAreaCount來(lái)計(jì)算出Shape集合的面積總數(shù),那么需要在<>里面加入怎樣的限制才能做到?
答案是Collection extends Shape>
public class DiamondInterfaceGeneric { public static void main(String[] args) { List sh = new ArrayList(); sh.add(new Circle(3.0)); sh.add(new Square(3.0)); System.out.println(totalArea(sh)); } public static double totalArea(Collection extends Shape> arr){ double total = 0; for(Shape s : arr){ if(s!=null) total+= s.getArea(); } return total; } }1.5 類型限界
在考慮一個(gè)更加極端的狀況,Comparable是泛型的,指定的類型為Shape,也即Comparable
答案是AnyType extends Comparable super AnyType>
public abstract class ShapeGeneric implements Comparable{ protected Double area; @Override public int compareTo(ShapeGeneric o) { return area.compareTo(o.area); } public Double getArea() { return area; } public void setArea(Double area) { this.area = area; } } public class CircleGeneric extends ShapeGeneric{ public CircleGeneric(double radius){ area = radius*radius*3.14; } } public class SquareGeneric extends ShapeGeneric{ public SquareGeneric(double len){ area = len*len; } } public class ComplexInterfaceGeneric { public static void main(String[] args) { ShapeGeneric[] sh = { new CircleGeneric(3.0), new SquareGeneric(3.0) }; System.out.println(findMax(sh)); } public static > AnyType findMax(AnyType[] arr){ checkArgument(arr.length>0); int max = 0; for(int i = 0 ;i 0){ max = i; } } return arr[max]; } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76322.html
摘要:虛擬機(jī)中并沒(méi)有泛型類型對(duì)象,所有的對(duì)象都是普通類。其原因就是泛型的擦除。中數(shù)組是協(xié)變的,泛型是不可變的。在不指定泛型的情況下,泛型變量的類型為該方法中的幾種類型的同一個(gè)父類的最小級(jí),直到。 引入泛型的主要目標(biāo)有以下幾點(diǎn): 類型安全 泛型的主要目標(biāo)是提高 Java 程序的類型安全 編譯時(shí)期就可以檢查出因 Java 類型不正確導(dǎo)致的 ClassCastException 異常 符合越早出...
摘要:接口也是集合中的一員,但它與接口有所不同,接口與接口主要用于存儲(chǔ)元素,而主要用于迭代訪問(wèn)即遍歷中的元素,因此對(duì)象也被稱為迭代器。迭代器的實(shí)現(xiàn)原理我們?cè)谥鞍咐呀?jīng)完成了遍歷集合的整個(gè)過(guò)程。 【Collection、泛型】 主要內(nèi)容 Collection集合 迭代器 增強(qiáng)for 泛型 教學(xué)目標(biāo) [ ] 能夠說(shuō)出集合與數(shù)組的區(qū)別 [ ] 說(shuō)出Collection集合的常用功能 [ ]...
摘要:總結(jié)泛型的類型必須是引用類型,不能是基本類型,泛型的個(gè)數(shù)可以有多個(gè),可以使用對(duì)創(chuàng)建對(duì)象時(shí)的泛型類型以及方法參數(shù)類型進(jìn)行限制,如使用關(guān)鍵字和對(duì)泛型的具體類型進(jìn)行向下限制或向上限制,最后一點(diǎn),可以聲明泛型數(shù)組,但是不能創(chuàng)建泛型數(shù)組的實(shí)例。 自從 JDK 1.5 提供了泛型概念,泛型使得開(kāi)發(fā)者可以定義較為安全的類型,不至于強(qiáng)制類型轉(zhuǎn)化時(shí)出現(xiàn)類型轉(zhuǎn)化異常,在沒(méi)有反省之前,可以通過(guò) Object...
摘要:泛型類泛型類和普通類的區(qū)別就是類定義時(shí),在類名后加上泛型聲明。泛型類的內(nèi)部成員方法就可以使用聲明的參數(shù)類型。 泛型是JDK 1.5的一項(xiàng)新特性,它的本質(zhì)是參數(shù)化類型(Parameterized Type),即所操作的數(shù)據(jù)類型在定義時(shí)被指定為一個(gè)參數(shù)。當(dāng)我們使用的時(shí)候給這個(gè)參數(shù)指定不同的對(duì)象類型,就可以處理不同的對(duì)象。這種參數(shù)類型可以用在類、接口和方法的創(chuàng)建中,分別稱為泛型類、泛型接口和...
摘要:靜態(tài)變量是被泛型類的所有實(shí)例所共享的。對(duì)于這個(gè)類型系統(tǒng),有如下的一些規(guī)則相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。在代碼中避免泛型類和原始類型的混用。參考泛型類型擦除 Java泛型總結(jié) Java泛型是JDK5引入的一個(gè)新特性,允許在定義類和接口的時(shí)候使用類型參數(shù)(type parameter)。聲明的類型參數(shù)在使用的時(shí)候使用具體的類型來(lái)替換。泛型最主要的應(yīng)用是在JDK5...
閱讀 949·2021-09-27 13:36
閱讀 905·2021-09-08 09:35
閱讀 1075·2021-08-12 13:25
閱讀 1447·2019-08-29 16:52
閱讀 2915·2019-08-29 15:12
閱讀 2736·2019-08-29 14:17
閱讀 2622·2019-08-26 13:57
閱讀 1021·2019-08-26 13:51