摘要:使用表示泛型中的基本思想就是可以通過使用像這樣適當的超類來實現泛型類。請看例子使用實現泛型使用接口類型表示泛型當有多個類要在一個通用的方法里表示泛型時,來表示可能就顯得捉襟見肘了,因為這個時候無法明確的知道用戶到底需要拆箱為哪種類。
1.1 使用Object表示泛型
Java中的基本思想就是可以通過使用像Object這樣適當的超類來實現泛型類。--《數據結構與算法分析 Java語言描述》
文中的超類也就是父類的意思。
使用Object這樣特殊的類來實現泛型是用到了Object是所有類的父類這個基本思想,但是這種實現方法帶來了兩個問題:
1. 沒有覆蓋基本類型,因為基本類型不是引用類型,所以不能用類表示基本類型,因此Object不是基本類型的父類 2. 在使用泛型后的對象時需要強制轉換,如果強轉失敗了也不會在編譯時報錯,只會在運行時報強轉失敗ClassCastException
這樣Object在實際使用中就不是一個非常完美的實現泛型的一個方法,但是提供了一個實現泛型的基本思想,就是通過父類來實現泛型。請看例子
/** * 使用Object實現泛型 */ 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 使用接口類型表示泛型
當有多個類要在一個通用的方法里表示泛型時,Object來表示可能就顯得捉襟見肘了,因為這個時候無法明確的知道用戶到底需要拆箱為哪種類。例如,String和Shape類的數組要用同一個findMax函數來找出最大的元素,這時在實現findMax的時候可能需要隨時要判斷入參的類型,這對于泛型的意義(減少代碼量)來說是毀滅性的。
因此這個時候需要找到String和Shape類的共同之處,抽象出一個接口,并在findMax里面用作入參來替代直接傳入String或Shape類。findMax的核心在于元素間的比較,在jdk中有一個接口java.lang.Comparable是滿足findMax需求的。
首先,定義一個實現了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; } }
然后派生出兩個具體的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函數
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函數中,因為已知入參是實現了Comparable接口的類,因此可以不用轉換直接使用compareTo函數,這是利用了接口的特性來實現的泛型。
System.out.println(findMax(comparables))會拋出ClassCastException異常,這是因為在compareTo中拆箱時無法將String類強轉為Shape類導致的。
以上兩種方式都存在編譯不會報錯,但是會在運行時報錯的問題,這樣就導致程序是不可控的,因為無法提前預知程序哪里會拋RuntimeException,所以需要一種泛型方法來強制使得異常能夠出現在編譯階段而不是運行時。
在java5中引入了泛型類的概念,通過<>運算符實現泛型。將第一個例子用<>運算符實現如下:
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增加的一種新的語言特性,菱形運算符:new DiamondGeneric<>(),在前面已經指定AnyType為String,因此在后面不必再指定類型。
想一種復雜的狀況,如果一個接口的多態實現需要在一個通用方法做同樣的操作,例如,Shape接口有一個area方法,有一個實現Circle,一個實現Square,需要一個findAreaCount來計算出Shape集合的面積總數,那么需要在<>里面加入怎樣的限制才能做到?
答案是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 類型限界
在考慮一個更加極端的狀況,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]; } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76322.html
摘要:虛擬機中并沒有泛型類型對象,所有的對象都是普通類。其原因就是泛型的擦除。中數組是協變的,泛型是不可變的。在不指定泛型的情況下,泛型變量的類型為該方法中的幾種類型的同一個父類的最小級,直到。 引入泛型的主要目標有以下幾點: 類型安全 泛型的主要目標是提高 Java 程序的類型安全 編譯時期就可以檢查出因 Java 類型不正確導致的 ClassCastException 異常 符合越早出...
摘要:接口也是集合中的一員,但它與接口有所不同,接口與接口主要用于存儲元素,而主要用于迭代訪問即遍歷中的元素,因此對象也被稱為迭代器。迭代器的實現原理我們在之前案例已經完成了遍歷集合的整個過程。 【Collection、泛型】 主要內容 Collection集合 迭代器 增強for 泛型 教學目標 [ ] 能夠說出集合與數組的區別 [ ] 說出Collection集合的常用功能 [ ]...
閱讀 946·2021-09-27 13:36
閱讀 893·2021-09-08 09:35
閱讀 1071·2021-08-12 13:25
閱讀 1442·2019-08-29 16:52
閱讀 2911·2019-08-29 15:12
閱讀 2732·2019-08-29 14:17
閱讀 2615·2019-08-26 13:57
閱讀 1018·2019-08-26 13:51