基础概念
类型参数: List<E>中的E就表示类型参数。
泛型:List<E> 具有一个或多个类型参数的类或接口就是泛型。
原生态类型:List 即不带任何实际类型参数的泛型名称,和java中没有引入泛型时完全一样。
无限制通配符类型: List<?> 类似于原生态类型,不过通配符类型是安全的,原生态类型则不安全,由于可以将任何元素放入到原生态类型中,从而破坏了限制要求,
对于无限制通配符类型,你无法将任何元素(null除外)放入到Collecttion<?>中.
由于为了向后兼容之前没有泛型的版本,java中采用泛型擦除的方式来实现。编译的时候有类型,在运行的时候泛型参数就不存在。
从而表现出泛型也有子类型 List<String>是原生态的子类型,而不是List<Object>的子类型。
列表:泛型则是不可变的,即不存在数组的那种性质,
数组:数组是协变的,其实就是说,如果sub是Super的子类型,那么数组类型sub[]就是Super[]的子类
这表明数组的有缺陷的,代码如下
/ 运行时异常 Object[] objectArray = new Long[1]; objectArray[0] = "I don fit"; // 不能编译 List<Object> arras = new ArrayList<Long>();
泛型数组问题
如下创建泛型、参数化类型、类型参数数组是非法的。new List<E>[] new List<String>[] new E[]
List<E>和List<String>是不可具体化的, 不可具体化类型是指运行时表示法包含的信息比编译时表示法包含的信息少。
但创建无限制通配符类型数组是合法的 new List<?>[] new Map<?,?>[]
由上可知直接 new E[]是非法的,那么可以通过两种方式创建类型参数数组。
1.通过new Object[12]数组,然后在强制转换成 E[]数组类型就可以,
public class myStack<E> { private E[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public myStack() { // 不能直接创建泛型数组 elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY]; System.out.println(elements.getClass().toString()); } public void push(E e) { ensureCapacity(); elements[size++] = e; } public E pop() { if (size == 0) throw new EmptyStackException(); E result = elements[--size]; System.out.println("pop" + result.getClass().toString()); // 释放数组元素 elements[size] = null; return result; } private void ensureCapacity() { // 原来的集合已经不可达,会被垃圾回收器直接回收 if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } public boolean isEmpty() { return size == 0 ? true : false; } public static void main(String... args) { // String[] text = (String[]) new Object[12]; // System.out.println(text.length); // text[0] = "12"; // System.out.println(text[0]); myStack<String> stack = new myStack<String>(); stack.push("zxj"); while (!stack.isEmpty()) System.out.println(stack.pop().toUpperCase()); } }
2.通过创建 Object[]数组,每次取出的时候,强制转换未E类型
public class myStack<E> { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public myStack() { // 不能直接创建泛型数组 elements = new Object[DEFAULT_INITIAL_CAPACITY]; System.out.println(elements.getClass().toString()); // String ss[] = (String[]) new Object[12]; } public void push(E e) { ensureCapacity(); elements[size++] = e; } public E pop() { if (size == 0) throw new EmptyStackException(); E result = (E) elements[--size]; System.out.println("pop" + result.getClass().toString()); // 释放数组元素 elements[size] = null; return result; } private void ensureCapacity() { // 原来的集合已经不可达,会被垃圾回收器直接回收 if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } public boolean isEmpty() { return size == 0 ? true : false; } public static void main(String... args) { // String[] text = (String[]) new Object[12]; // System.out.println(text.length); // text[0] = "12"; // System.out.println(text[0]); myStack<String> stack = new myStack<String>(); stack.push("zxj"); while (!stack.isEmpty()) System.out.println(stack.pop().toUpperCase()); } }
禁止数组类型的未受检转换比禁止标量的更加危险,因此第二种更加合理