Java泛型的实现 提到Java的泛型一般人都会想到类型擦除(Type Erasure)机制。 如果你没想到,请去补一补。。。。
创建泛型数组 Java不允许创建泛型数组
1 Hello<String>[] hello = new Hello<String>[12 ];
这句话是编译不通过的。
答案有点让人失望的简单,因为数组必须知道里面的元素是什么。
但是这句话很误导人 真的不允许创建我们想要的泛型数组么,那种可以编译时检查的泛型数组。 答案是可以的,不过得通过一些技巧。
好,那么怎么创建呢。
1 2 3 4 @SuppressWarnings ("unchecked" )public static void main (String[] args) { List<String>[] lists = (List<String>[])new ArrayList[12 ]; }
这是其中之一的方法,可能有人觉得这样和
1 2 3 public static void main (String[] args) { List[] lists = new ArrayList[12 ]; }
没有区别。
划重点!!!!! 第一种方法相对于第二种方法还是具有编译时类型检查的。
泛型类中的泛型数组 怎么在范型类中创建泛型数组呢
其实第一来说没必要, 比如在ArrayList中维护的底层的数组是Object数组。
如果你硬是想创建,可以这样
1 T[] arr = (T[])new Object[12 ];
很多人或许觉得奇怪为什么,这不是向上转型么。
然后举出例子为什么
1 List<String>[] list = (List<String>[])new Object[10 ];
这种就不行。
答案还是Java泛型实现的核心类型擦除。 在编译时
1 2 3 T[] arr = (T[])new Object[12 ];
这样就是毫无问题。
协变,逆变 协变和逆变
当A是B的子类时,如果有f(A)也是f(B)的子类,那么f叫做协变; 当A是B的子类时,如果有f(B)是f(A)的子类,那么f叫做逆变;
数组是协变的。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Genetic { public static void main(String[] args) { Fruit[] fruits; Apple[] apples = new Apple[10]; fruits = apples; } } class Apple extends Fruit { } class Fruit { }
这段代码能编译通过。
但是这一段就不行了
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Genetic { public static void main (String[] args) { List<Fruit> list; List<Apple> list1 = new ArrayList<>(); list = list1; } } class Apple extends Fruit { } class Fruit { }
就是说List和List没有关系。
java通过通配符解决这个问题,还是上面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Genetic { public static void main (String[] args) { List<? extends Fruit> list; List<Apple> list1 = new ArrayList<>(); list = list1; } } class Apple extends Fruit { } class Fruit { }
extends解决了协变的问题,逆变通过super解决。
但是,没有那么简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Genetic { public static void main (String[] args) { List<? extends Fruit> list = new ArrayList<Apple>(); } } class Apple extends Fruit { } class Fruit { }
<? extends Fruit>不是表示里面的元素只要是Fruit的子类就行,而是加入的元素必须可以向上转型为Fruit的任意一个子类。 那么大概只有null可以add了。
同样的<? super Fruit>表示里面元素可以转型为Fruid的任意一个父类。
要想可以编译通过,我们可以使用super
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Genetic { public static void main (String[] args) { List<? super Fruit> list = new ArrayList<>(); list.add(new Apple()); } } class Apple extends Fruit { } class Fruit { }
那到底应该什么时候用super和extends呢。 Effective Java中总结了一个原则
producer-extends, consumer-super
看看ArrayList的源码就知道了
1 2 3 4 5 6 7 8 public boolean addAll (Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); System.arraycopy(a, 0 , elementData, size, numNew); size += numNew; return numNew != 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 public void forEach (Consumer<? super E> action) { Objects.requireNonNull(action); final int expectedModCount = modCount; @SuppressWarnings ("unchecked" ) final E[] elementData = (E[]) this .elementData; final int size = this .size; for (int i=0 ; modCount == expectedModCount && i < size; i++) { action.accept(elementData[i]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } }