泛型是指參數化類型的能力,可以定義泛型類型的類、接口或方法,隨后編譯器會用具體的類型來替換它
使用泛型的主要優點是:能夠在編譯時而不是在運行時檢測錯誤
package java.lang; public interface Comparable { //JDK1.5之前 public int compareTo(Object o);}package java.lang; public interface Comparable<T> { //JDK1.5之后 public int compareTo(T o);}
新泛型類型在編譯時檢測到可能的錯誤:
Comparable c = new Date();System.out.泛型類型必須是引用類型,不能用像int、double或char這樣的基本類型來替換泛型類型:
ArrayList<int> intlist = new ArrayList<int>(); //error必須使用:
ArrayList<Integer> intList = new ArrayList<Integer>();java會自動打包操作:
ArrayList<Integer> intList = new ArrayList<Integer>();intList.add(5); //java會自動地將5包裝為new Integer(5)定義泛型類和接口下面看一個泛型類的例子:
public class GenericStack<E> { ArrayList<E> list = new ArrayList<E>(); public int getSize() { return list.size(); } public E peek() { return list.get(getSize() - 1); } public void push(E o) { list.add(o); } public E pop() { E o = list.get(getSize() - 1); list.remove(getSize() - 1); return o; } public boolean isEmpty() { return list.isEmpty(); }}View Code向棧中添加元素:
GenericStack<String> stack1 = new GenericStack<String>();stack1.push("London");stack1.push("Paris");stack1.push("Berlin");GenericStack<Integer> stack2 = new GenericStack<Integer>();stack2.push(1);stack2.push(2);stack2.push(3);定義泛型方法public static void main(String args[]){ Integer[] integers = {1, 2, 3, 4, 5}; String[] strings = {"London", "Paris", "New York", "Austin"}; print(integers); print(strings);} public static <E> void print(E[] list) { for(int i = 0; i < list.length; i++) System.out.print(list[i] + " "); System.out.println();}通配泛型下面的例子說明了為什么要使用通配泛型:
public class Main{ public static void main(String args[]) { GenericStack<Integer> intStack = new GenericStack<Integer>(); intStack.push(1); intStack.push(2); intStack.push(-2); System.out.print("The max number is " + max(intStack)); } public static double max(GenericStack<Number> stack) { double max = stack.pop().doubleValue(); while(!stack.isEmpty()) { double value = stack.pop().doubleValue(); if(value > max) max = value; } return max; } }標記行會產生編譯錯誤,因為intStack不是GenericStack<Number>的實例,盡管Integer是Number的子類型,但是GenericStack<Integer> 并不是 GenericStack<Number> 的子類型,為了避免這個問題,可以使用通配泛型類型 ,通配泛型類型有三種形式:
非受限通配:? (它和? extends Object是一樣的)
受限通配:? extends T (表示T或T的一個未知子類型)
下限通配: ? super T (表示T或T的一個未知父類型)
使用受限通配修改后的代碼如下:
public class Main{ public static void main(String args[]) { GenericStack<Integer> intStack = new GenericStack<Integer>(); intStack.push(1); intStack.push(2); intStack.push(-2); System.out.print("The max number is " + max(intStack)); } public static double max(GenericStack<? extends Number> stack) { double max = stack.pop().doubleValue(); while(!stack.isEmpty()) { double value = stack.pop().doubleValue(); if(value > max) max = value; } return max; } }再看下面的一個例子:
public class Main{ public static void main(String args[]) { GenericStack<Integer> intStack = new GenericStack<Integer>(); intStack.push(1); intStack.push(2); intStack.push(-2); print(intStack); } public static void print(GenericStack<?> stack) { while(!stack.isEmpty()) { System.out.print(stack.pop() + " "); } } }什么時候使用下限通配?看下面的例子:
public class Main{ public static void main(String args[]) { GenericStack<String> stack1 = new GenericStack<String>(); GenericStack<Object> stack2 = new GenericStack<Object>(); stack2.push("Java"); stack2.push(2); stack1.push("Sun"); add(stack1, stack2); print(stack2); } public static<T> void add(GenericStack<T> stack1, GenericStack<? super T> stack2) { while(!stack1.isEmpty()) { stack2.push(stack1.pop()); } } public static void print(GenericStack<?> stack) { while(!stack.isEmpty()) { System.out.print(stack.pop() + " "); } } }消除泛型和對泛型的限制泛型是一種稱為類型消除的方法實現的,泛型信息在運行時是不可用的,這種方法可以使泛型代碼向后兼容使用原始類型的遺留代碼
泛型存在于編譯時。一旦編譯器確認泛型類型是安全使用的,就將它轉換為原始類型
例如下面的代碼:
ArrayList<String> list = new ArrayList<String>();list.add("Oklahoma");String state = list.get(0);被翻譯成如下的代碼的原始類型:
ArrayList list = new ArrayList();list.add("Oklahoma");String state = (String)list.get(0);使用泛型類型是有一些限制的:
限制1、不能使用new E()
不能使用泛型類型參數創建實例:E object = new E()
限制2、不能使用new E()
不能使用泛型類型參數創建數組,如:E[] elements = new E[capacity];
可以通過創建一個Object類型的數組,然后將它的類型轉化為E[]來規避這個限制,如:E[] elements = (E[]) new Object[capacity];
限制3、在靜態環境中不允許類的參數是泛型類型
由于泛型類的所有實例都有相同的運行時類,所以泛型類的靜態變量和方法是被它的所有實例所共享的,下面的代碼非法:
public calss Test<E> { public static Void m(E o1) { } public static E o1; static { E o2; }}限制4、異常類不能是泛型的
新聞熱點
疑難解答