标签:
一、首先要强调,数组不支持泛型
1.数组是编译期间检查并且要求有确定类型存在, 而泛型由于擦除的存在, 类型信息被删除, 所以数组不支持泛型。
见下例:
1 import java.lang.reflect.Array; 2 import java.util.Arrays; 3 4 /** 5 * 创建一个类,它支持泛型, 本意是希望提供一个方法,该方法 6 * 能够根据泛型来返回一个该类型的数组 7 */ 8 public class ArrayMarker<T> { 9 private Class<T> kind; 10 public ArrayMarker(Class<T> kind) { 11 this.kind = kind; 12 } 13 14 T[] create(int size) {//创建方法 15 return (T[])Array.newInstance(kind, size); 16 } 17 18 public static void main(String[]args) { 19 ArrayMarker<String> stringMarker = 20 new ArrayMarker<String>(String.class); 21 22 String[] stringArray = stringMarker.create(9); 23 System.out.println(Arrays.toString(stringArray)); 24 } 25 }
结果如下:
可以看到, 虽然尝试传递类型, 但是由于泛型的存在将类型信息删除, 最终生成的只是null。
2.泛型删除的只是类型信息,而不是值本身
这点需要注意, 泛型并不会删除传过去的值本身, 只是传过去的值对它来说不再有原来的类型信息, 见下例:
1 public class ArrayMarker<T> { 2 private Class<T> kind; 3 public ArrayMarker(Class<T> kind) { 4 this.kind = kind; 5 } 6 7 T[] create(int size) { 8 return (T[])Array.newInstance(kind, size); 9 } 10 11 T[] create2(T t,int size) { 12 T[] tarr = (T[])Array.newInstance(kind, size); 13 for(int i=0;i<tarr.length;i++) { 14 tarr[i] = t;//值设置 15 } 16 return tarr; 17 } 18 19 public static void main(String[]args) { 20 ArrayMarker<String> stringMarker = 21 new ArrayMarker<String>(String.class); 22 23 String[] stringArray = stringMarker.create2("hello",4); 24 System.out.println(Arrays.toString(stringArray)); 25 } 26 }
结果如下:
并不是说由于擦除的存在,导致T本身,就变成Object了, 只是说它的具体类型信息Class里面的东西,被擦除掉, 但是方法指针什么还在,还能够调用a方法, 还能够显示T的值,只是T.t.getClass()的时候,返回的已经不是Weight 的类型信息了,它的类型信息已经被擦除 。
如果要关联上泛型来使用容器, 不要使用数组, 使用Collection,Map。
3.关于泛型和数组,再看两个例子:
二、泛型的边界
1.extends关键字
前面的博客中,有提到使用<T extends HasF> 这种形式来确定边界 ,下面是一个更复杂的例子:
1 import java.awt.Color; 2 //定义一个颜色接口 3 interface HasColor { 4 Color getColor(); 5 } 6 7 //定义一个着色类,注意 T这里继承的是接口,说明T也是接口类型 8 class Colored<T extends HasColor> { 9 T item; 10 Colored(T item) { 11 this.item = item; 12 } 13 T getItem() { 14 return this.item; 15 } 16 17 Color color() { 18 return item.getColor(); 19 } 20 } 21 22 //定义一个三维类 23 class Dimension { 24 public int x,y,z; 25 } 26 27 28 //这里报错,首先了解到可以用&来这么写, 另一个问题就是如果这么写,必须要先写类,后写接口 29 //class ColoredDimension<T extends HasColor & Dimension> { 30 // 31 //} 32 33 class ColoredDimension<T extends Dimension & HasColor > { 34 T item; 35 public ColoredDimension(T item) { 36 this.item = item; 37 } 38 39 T getItem() { 40 return this.item; 41 } 42 43 Color color() { 44 return item.getColor(); 45 } 46 47 int getX() { 48 return item.x; 49 } 50 51 int getY() { 52 return item.y; 53 } 54 55 int getZ() { 56 return item.z; 57 } 58 59 } 60 61 interface Weight { 62 int weight(); 63 } 64 65 /** 66 * 这里,还能够在泛型中extends关键字后面写多个接口 67 */ 68 class Solid<T extends Dimension & HasColor & Weight> { 69 T item; 70 public Solid(T item) { 71 this.item = item; 72 } 73 74 T getItem() { 75 return this.item; 76 } 77 78 Color color() { 79 return item.getColor(); 80 } 81 82 int getX() { 83 return item.x; 84 } 85 86 int getY() { 87 return item.y; 88 } 89 90 int getZ() { 91 return item.z; 92 } 93 94 public int weight() { 95 return item.weight(); 96 } 97 } 98 99 /** 100 * 这里,继承Dimension ,并且实现HasColor,Weight接口,但是没采用泛型 101 */ 102 class Bounded extends Dimension implements HasColor,Weight { 103 public Color getColor() { 104 return null; 105 } 106 107 public int weight() { 108 return 0; 109 } 110 } 111 112 public class BasicBounds { 113 public static void main(String[] agrs) { 114 Solid<Bounded> solid = new Solid<Bounded>(new Bounded()); 115 116 System.out.println(solid.color()); 117 System.out.println(solid.getY()); 118 System.out.println(solid.weight()); 119 } 120 }
简单的理解,就是泛型可以用<T extends HasColor & Dimension> 这种形式来确定边界 ,extends哪个,就可以仍然拥有哪个类的方法(可以参考之前博客的例子) ,并且extends后面也可以接接口, 用&来连接。
但是不支持<T implements Dimension>这种形式。
2.extends关键字的反面 super关键字 (逆变)
首先看一个例子:
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class ConvariantArrays { 5 public static void main(String[] args) { 6 List<? extends Father> list = new ArrayList<Son>(); 7 list.add(null); 8 // list.add(new Father()); //报错 9 // list.add(new Son()); //报错 10 // list.add(new Object()); //报错 11 12 } 13 } 14 15 class Father {} 16 17 class Son extends Father {}
这里看似是只要extends Father的类都能放入,但是事实上除了放入null, 其他包括放Object都会报错。
但是类似的如果用super关键字
1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class SuperTypeWildcards { 5 6 public static void main(String[] args) { 7 List<? super Apple> list = new ArrayList<Apple>(); 8 list.add(new Apple()); 9 } 10 }
这里可以成功。如果大神路过,求给个解释一下。
标签:
原文地址:http://www.cnblogs.com/kaiguoguo/p/4818809.html