讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議18:避免instanceof非預期結果 >

建議18:避免instanceof非預期結果

instanceof是一個簡單的二元操作符,它是用來判斷一個對象是否是一個類實例的,其操作類似於>=、==,非常簡單,我們來看段程序,代碼如下:


public class Client{

public static void main(Stringargs){

//String對象是否是Object的實例

boolean b1="Sting"instanceof Object;

//String對象是否是String的實例

boolean b2=new String()instanceof String;

//Object對象是否是String的實例

boolean b3=new Object()instanceof String;

//拆箱類型是否是裝箱類型的實例

boolean b4='A'instanceof Character;

//空對象是否是String的實例

boolean b5=null instanceof String;

//類型轉換後的空對象是否是String的實例

boolean b6=(String)null instanceof String;

//Date對象是否是String的實例

boolean b7=new Date()instanceof String;

//在泛型類中判斷String對象是否是Date的實例

boolean b8=new GenericClass<String>().isDateInstance("");

}

}

class GenericClass<T>{

//判斷是否是Date類型

public boolean isDateInstance(T t){

return t instanceof Date;

}

}


就這麼一段程序,instanceof的所有應用場景都出現了,同時問題也產生了:這段程序中哪些語句會編譯通不過?我們一個一個地來解說。

"Sting" instanceof Object

返回值是true,這很正常,"String"是一個字符串,字符串又繼承了Object,那當然是返回true了。

new String()instanceof String

返回值是true,沒有任何問題,一個類的對象當然是它的實例了。

new Object()instanceof String

返回值是false, Object是父類,其對像當然不是String類的實例了。要注意的是,這句話其實完全可以編譯通過,只要instanceof關鍵字的左右兩個操作數有繼承或實現關係,就可以編譯通過。

'A' instanceof Character

這句話可能有讀者會猜錯,事實上它編譯不通過,為什麼呢?因為'A'是一個char類型,也就是一個基本類型,不是一個對象,instanceof只能用於對象的判斷,不能用於基本類型的判斷。

null instanceof String

返回值是false,這是instanceof特有的規則:若左操作數是null,結果就直接返回false,不再運算右操作數是什麼類。這對我們的程序非常有利,在使用instanceof操作符時,不用關心被判斷的類(也就是左操作數)是否為null,這與我們經常用到的equals、toString方法不同。

(String)null instanceof String

返回值是false,不要看這裡有個強制類型轉換就認為結果是true,不是的,null是一個萬用類型,也可以說它沒類型,即使做類型轉換還是個null。

new Date()instanceof String

編譯通不過,因為Date類和String沒有繼承或實現關係,所以在編譯時直接就報錯了,instanceof操作符的左右操作數必須有繼承或實現關係,否則編譯會失敗。

new GenericClass<String>(). isDateInstance("")

編譯通不過?非也,編譯通過了,返回值是false, T是個String類型,與Date之間沒有繼承或實現關係,為什麼"t instanceof Date"會編譯通過呢?那是因為Java的泛型是為編碼服務的,在編譯成字節碼時,T已經是Object類型了,傳遞的實參是String類型,也就是說T的表面類型是Object,實際類型是String,那"t instanceof Date"這句話就等價於"Object instance of Date"了,所以返回false就很正常了。

就這麼一個簡單的instanceof,你答對幾個?