但是不能对List<? extends Shape> shapes直接进行操作:
1 import java.util.List; 2 import java.util.ArrayList; 3 4 public class Canvas{ 5 //同时在画布上绘制多个形状 6 public void drawAll(List<? extends Shape> shapes){ 7 for(Shape s : shapes){ 8 s.draw(this); 9 } 10 } 11 12 public void addRectangle(List<? extends Shape> shapes){ 13 //下面代码引起编译错误 14 shapes.add(0, new Rectangle()); 15 } 16 17 public static void main(String[] args){ 18 //下面的代码将会引起错误 19 //drawAll方法的形参类型是List<Shape>而不是List<Circle> 20 List<Circle> circleList = new ArrayList<>(); 21 Canvas c = new Canvas(); 22 //不能把List<Circle>当成List<Shape>使用 23 c.drawAll(circleList); 24 } 25 } View Code设定类型形参的上限:
Java泛型不仅允许在使用通配符形参时设定上限,而且还可以在定义类型形参时设定上限,用于表示给该类型形参的实际类型要么是该上限类型,要么是该上限类型的子类
1 //定义Apple类时使用了泛型声明 2 public class Apple<T extends Number>{ 3 //使用T类型形参定义实例变量 4 private T info; 5 public static void main(String[] args){ 6 Apple<Integer> ai = new Apple<>(); 7 Apple<Double> ad = new Apple<>(); 8 //下面代码将引发编译异常,下面代码试图把String类型传给T形参 9 //但String不是Number的子类型,所以引起编译错误 10 Apple<String> as = new Apple<>(); 11 } 12 } View Code在一种极端情况下,程序需要为类型形参设定多个上限(至多有一个父类上限,可以有多个接口上限),表明该类型形参必须是其父类的子类(父类本身也可以),并且
实现了多个上限接口:
1 //表明T类型必须是Number类或其子类,并必须实现java.io.Serializable接口 2 public class Apple<T extends Number & java.io.Serializable>{ 3 ... 4 } View Code与类同时继承父类、实现接口类似,为类型形参指定多个上限时,所有接口上限必须位于类上限之后。即若需要为类型形参指定类上限,类上限必须位于第一位。
泛型方法:
Java5提供了对泛型方法的支持。
定义泛型方法格式:
1 //泛型方法,在声明方法时定义一个或多个类型形参,格式如下 2 修饰符 <T, S> 返回值类型 方法名(形参列表){ 3 //方法体... 4 } View Code泛型方法举例:
1 static <T> void fromArrayToCollection(T[] a, Collection<T> c){ 2 for(T o : a){ 3 c.add(o); 4 } 5 } View Code泛型方法完整程序用法:
1 import java.util.Collection; 2 import java.util.ArrayList; 3 4 public class GenericMethodTest{ 5 //声明一个泛型方法,该泛型方法中带一个T类型形参 6 static <T> void fromArrayToCollection(T[] a, Collection<T> c){ 7 for (T o : a){ 8 c.add(o); 9 } 10 } 11 12 public static void main(String[] args){ 13 Object[] oa = new Object[100]; 14 Collection<Object> co = new ArrayList<>(); 15 //下面代码中T代表Object类型 16 fromArrayToCollection(oa, co); 17 String[] sa = new String[100]; 18 Collection<String> cs = new ArrayList<>(); 19 //下面代码中T代表String类型 20 fromArrayToCollection(sa, cs); 21 //下面代码中T代表Object类型 22 fromArrayToCollection(sa, co); 23 Integer[] ia = new Integer[100]; 24 Float[] fa = new Float[100]; 25 Number[] na = new Number[100]; 26 Collection<Number> cn = new ArrayList<>(); 27 //下面代码中T代表Number类型 28 fromArrayToCollection(ia, cn); 29 //下面代码中T代表Number类型 30 fromArrayToCollection(fa, cn); 31 //下面代码中T代表Number类型 32 fromArrayToCollection(na, cn); 33 //下面代码中T代表Object类型 34 fromArrayToCollection(na, co); 35 //下面代码中T代表String类型,但na是一个Number数组 36 //因为Number既不是String类型 37 //也不是它的子类,所以出现编译错误 38 fromArrayToCollection(na, cs); 39 } 40 } View Code数组T[]可以是其子类数组,Collection<T>只能是同类T。