Java 從1.5 版加入泛型的功能後,一直有個潛在的使用問題,那就是 Heap Pollution。
我們先來看看下面這個範例:
package idv.jacky.ironman4.day25;
import java.util.Arrays;
import java.util.List;
public class Day25Example1 {
public static void main(String[] args) {
List numbers = Arrays.asList(args);
System.out.printf("Sum = %d%n", Util.sum(numbers));
}
}
package idv.jacky.ironman4.day25;
import java.util.List;
public class Util {
public static int sum(List<Integer> ls) {
int sum = 0;
for(Integer i : ls)
sum += i;
return sum;
}
}
你應該一眼就能看出來上面這個範例程式哪兒出了問題,問題就在於 Util.sum 方法只能接受 List<Integer> 的參數,但我們卻在第10行把一個 List 物件傳進去,而 List 物件則是透過 Arrays.asList 的方法,把 main 方法 的參數 args 字串陣列,轉成 List 物件。
程式在編譯時,Java 編譯器會丟出一個警告訊息:
javac Day25Example1.java
Note: Day25Example1.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
意思是說程式裡有個未受檢查或不安全的程式碼,建議你在編譯時加上 -Xlint:unchecked 來看詳細的資料。
javac -Xlint:unchecked Day25Example1.java
Day25Example1.java:10: warning: [unchecked] unchecked conversion
found : java.util.List
required: java.util.List<java.lang.Integer>
System.out.printf("Sum = %d%n", sum(numbers));
^
1 warning
Java 編譯器有檢查到,sum 方法的參數型別應該是 List<Integer>,但你給的是 List。
程式依然可以編譯成功,但執行時就會有例外出現:
所以 Heap Pollution 指的就是將一個未定參數型別的 Collection 物件,指定給一個有指定參數型別的 Collection 物件後,所隱藏的潛在問題。
既然知道這樣會有潛在的危險,因為我們不能確定所有呼叫 sum 方法的人,傳進來的都是 List<Integer> 物件,那為什麼不能在編譯時就給個錯誤,不讓程式編譯成功呢?主要的原因是,Java 無法知道誰會呼叫 sum 方法。我們的範例很簡單,你一下就看出來哪邊有問題,但今天如果 Util 類別是要給別人使用的,你並沒有辦法知道別人會不會正確的使用它。而 Java 程式裡變數的型別檢查,都是在編譯時其做的,在執行時期,是完全沒有型別資料的。一直要到發生例外時,我們才知道問題出在哪。
所以當你在編譯 Java 程式碼時,如果要你使用 -Xlint:unchecked 來察看詳細的警告資料時,請花點時間看一下,修正可能會發生錯的程式碼,這樣能確保你的程式能更安全、穩固地執行。