摘要:使用表示泛型中的基本思想就是可以通过使用像这样适当的超类来实现泛型类。请看例子使用实现泛型使用接口类型表示泛型当有多个类要在一个通用的方法里表示泛型时,来表示可能就显得捉襟见肘了,因为这个时候无法明确的知道用户到底需要拆箱为哪种类。
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]; } }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/76322.html
摘要:虚拟机中并没有泛型类型对象,所有的对象都是普通类。其原因就是泛型的擦除。中数组是协变的,泛型是不可变的。在不指定泛型的情况下,泛型变量的类型为该方法中的几种类型的同一个父类的最小级,直到。 引入泛型的主要目标有以下几点: 类型安全 泛型的主要目标是提高 Java 程序的类型安全 编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常 符合越早出...
摘要:接口也是集合中的一员,但它与接口有所不同,接口与接口主要用于存储元素,而主要用于迭代访问即遍历中的元素,因此对象也被称为迭代器。迭代器的实现原理我们在之前案例已经完成了遍历集合的整个过程。 【Collection、泛型】 主要内容 Collection集合 迭代器 增强for 泛型 教学目标 [ ] 能够说出集合与数组的区别 [ ] 说出Collection集合的常用功能 [ ]...
阅读 922·2021-09-27 13:36
阅读 839·2021-09-08 09:35
阅读 1040·2021-08-12 13:25
阅读 1406·2019-08-29 16:52
阅读 2871·2019-08-29 15:12
阅读 2681·2019-08-29 14:17
阅读 2568·2019-08-26 13:57
阅读 979·2019-08-26 13:51