如何判斷是不是誰的誰?Java有一個 instanceof 操作符(關係操作符)可以做這件事。
public static void main(String[] args) {String s = "Hello World!";System.out.println(s instanceof String);}
列印出結果:
true
可是如果你的那個誰不存在呢?請看代碼:
public static void main(String[] args) {String s = null;System.out.println(s instanceof String);}
很多人都會異口同聲的說:
false
你答對了!
JSL-15.20.2 規定
At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast to the ReferenceType without raising a ClassCastException. Otherwise the result is false.註:在運行期,如果關係表達式不為空,並且類型轉換時不會拋出ClassCastException異常時,instanceof表達式返回結果為真,否則結果為假
牽線之亂點鴛鴦譜
如果沒有任何關係的兩個類使用 instanceof 會如何?
class Point { int x, y; }class Element { int atomicNumber; }public class InstanceofTest {public static void main(String[] args) {Point p = new Point();Element e = new Element();if (e instanceof Point) {System.out.println("匹配成功!");}else {System.out.println("匹配不成功");}}}
不少人會說:「匹配不成功」
抱歉,你又掉進坑裡了,這個會報編譯錯誤
JSL-15.20.2規定
The type of the RelationalExpression operand of the instanceof operator must be a reference type or the null type, or a compile-time error occurs.註:instanceof操作符的關係表達式操作數的類型必須是一個引用類型或者null類型,否則拋出編譯錯誤It is a compile-time error if the ReferenceType mentioned after the instanceof operator does not denote a reference type that is reifiable。註:如在instanceof操作符後面提及的引用類型表示的不是可具化(§4.7)引用類型.就會拋出編譯錯誤。If a cast of the RelationalExpression to the ReferenceType would be rejected as a compile-time error (§15.16), then the instanceof relational expression likewise produces a compile-time error. In such a situation, the result of the instanceof expression could never be true.註:如從關係表達式到引用類型的強制類型轉換將作為編譯時錯誤而拒絕,那麼 instanceof 關係表達式也就同樣地產生編譯時錯誤。這種情況下,instanceof 表達式的結果也永遠不會是真。
當然,cast 也會是編譯錯誤
class Point { int x, y; }class Element { int atomicNumber; }public class InstanceofTest {public static void main(String[] args) {Point p = new Point();Element e = new Element();p = (Point)e; // compile-time error}}
牽線之暗藏玄機
編譯器並不是萬能的,並不能檢測出所有問題,看下面:
class Point { int x, y; }class Element { int atomicNumber; }public class InstanceofTest {public static void main(String[] args) {Point p = new Point();//Element e = new Element();p = (Point) new Object();System.out.println(p instanceof Point);}}
猛一看,沒事問題,編譯也沒有問題,可是運行時報錯:
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to Point
上面的程序展示了,當要被轉型的表達式的靜態類型是轉型類型的超類時,轉型操作符的行為。與 instanceof 操作相同,如果在一個轉型操作中的兩種類型都是類,那麼其中一個必須是另一個的子類型。儘管對我們來說,這個轉型很顯然會失敗,但是類型系統還沒有強大到能夠洞悉表達式 new Object() 的運行期類型不可能是 Point 的一個子類型。因此,該程序將在運行期拋出 ClassCastException 異常。
牽線之競爭激烈
關係操作符 instanceof 可不是市場上唯一的選擇,另外一個背靠大山的傢伙要注意了:
Class 的方法
booleanisInstance(Object obj)Determines if the specified Object is assignment-compatible with the object represented by this Class.
那麼什麼時候該用 instanceof 什麼時候該用 isInstance 呢 ? 我的理解是:
instanceof 偏向於比較 class之間
isInstance 偏向於比較 instance 和 class 之間
stackoverflow 也有此問題的解答:
I take that to mean that isInstance() is primarily intended for use in code dealing with type reflection at runtime. In particular, I would say that it exists to handle cases where you might not know in advance the type(s) of class(es) that you want to check for membership of in advance (rare though those cases probably are).註:我認為這意味著isInstance()主要用於在運行時處理類型反射的代碼中。特別是,我想說它的存在是為了處理,您可能事先不知道您想要檢查的類的類型(s)(儘管這些情況可能很少)的情況。For instance, you can use it to write a method that checks to see if two arbitrarily typed objects are assignment-compatible, like:註:例如,您可以使用它來編寫一個方法,檢查兩個任意類型的對象是否兼容,如:
public boolean areObjectsAssignable(Object left, Object right) {return left.getClass().isInstance(right);}
In general, I』d say that using instanceof should be preferred whenever you know the kind of class you want to check against in advance. In those very rare cases where you do not, use isInstance() instead.註:一般來說,我想說,當您知道要提前檢查的類的類型時,應該首選使用instanceof。在不使用isInstance()的非常罕見的情況下,可以使用isInstance()
總結
回歸本源,instanceof 是 Java 中的二元運算符,左邊是對象,右邊是類;當對象是右邊類或子類所創建對象時,返回 true;否則,返回 false。