開始完全一頭霧水呀,后面看了Java指令集的介紹,逐漸理解了。
https://www.zhihu.com/question/21574535/answer/18998914
下面這個答案比較直白
你在面月薪10000的Java高級研發職位。面試官對JVM有一些了解,想讓你說說JVM會如何實現 instanceof 指令。
但他可能也沒看過實際的JVM是怎么做的,只是臆想過一下而已。JVM的規定就是“底層”。這種情況就給他JVM規范對 instanceof 指令的定義就好: Chapter 6. The Java Virtual Machine Instruction Set, JVM規范Java SE 7版 根據規范來臆想一下實現就能八九不離十的混過這題了。 地址: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.instanceof
上面指令的定義詳細解釋如下(解釋和重要點已經飄紅指出):
instanceof
The objectref, which must be of type reference
, is popped from the operand stack. The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), where the value of the index is (indexbyte1 <<
8) | indexbyte2. The run-time constant pool item at the index must be a symbolic reference to a class, array, or interface type.
If objectref is null
, the instanceof instruction pushes an int
result of 0 as an int
on the operand stack.
意思是左側是null,就返回false.(另外,右側不能為null)
Otherwise, the named class, array, or interface type is resolved (§5.4.3.1). If objectref is an instance of the resolved class or array or implements the resolved interface, the instanceof instruction pushes an int
result of 1 as an int
on the operand stack; otherwise, it pushes an int
result of 0.
這個只是概述,下面是詳細解釋。分為多鍾情況。
The following rules are used to determine whether an objectref that is not null
is an instance of the resolved type: If S is the class of the object referred to by objectref and T is the resolved class, array, or interface type, instanceof determines whether objectref is an instance of T as follows:
-
If S is an ordinary (nonarray) class, then:
-
If T is a class type, then S must be the same class as T, or S must be a subclass of T;
-
If T is an interface type, then S must implement interface T.
-
-
If S is an interface type, then:
-
If T is a class type, then T must be
Object
. -
If T is an interface type, then T must be the same interface as S or a superinterface of S.
-
-
If S is a class representing the array type SC
[]
, that is, an array of components of type SC, then:-
If T is a class type, then T must be
Object
. -
If T is an interface type, then T must be one of the interfaces implemented by arrays (JLS §4.10.3).
-
If T is an array type TC
[]
, that is, an array of components of type TC, then one of the following must be true:-
TC and SC are the same primitive type.
-
TC and SC are reference types, and type SC can be cast to TC by these run-time rules.
-
-
During resolution of the symbolic reference to the class, array, or interface type, any of the exceptions documented in §5.4.3.1 can be thrown.
The instanceof instruction is very similar to the checkcast instruction (§checkcast). It differs in its treatment of null(上面提到,左側null會直接返回false)
, its behavior when its test fails (checkcast throws an exception, instanceof pushes a result code), and its effect on the operand stack.
下面這個答案比較“晦澀”
你在面試月薪10000以上的Java資深研發職位,注重性能調優啥的。這種職位雖然不直接涉及JVM的研發,但由於性能問題經常源自“抽象泄漏”,
對實際使用的JVM的實現的思路需要有所了解。面試官對JVM的了解可能也就在此程度。
對付這個可以用一篇論文:Fast subtype checking in the HotSpot JVM。
之前有個討論帖里討論過對這篇論文的解讀:請教一個share/vm/oops下的代碼做fast subtype check的問題
其中提到了 “抽象泄露”,后面會單開文章分析。
再看下面的代碼例子(http://jurisp.iteye.com/blog/815704)
String s = null; System.out.println(s instanceof Object); // false System.out.println(s instanceof String); // false // 下面的不能通過編譯 Incompatible conditional operand types String and String[] // boolean as = (s instanceof String[]); // 不能編譯 Syntax error on token "null", invalid ReferenceType // System.out.println(s instanceof null); // 不能編譯 Incompatible conditional operand types TypeInstanceTest and String//System.out.println(new Solution() instanceof String); System.out.println(new String() instanceof String); //true System.out.println(new String() instanceof Object); //true // 會拋出異常 Solution test = (Solution) new Object();
而運行結果如下:
false false true true Exception
說明不是隨便兩個類型之間都能用instanceof的,如果兩個操作數的類型都是類,其中一個必須是另一個的子類型。
另外,注意下面這段晦澀的表述。
訪問靜態方法,使用表達式作為限定符。表達式的值所引用的對象的運行期類型在確定哪一個方法被調用的時候不起作用,而且對象有標識符,其標識符也不起任何作用。
代碼示例如下:
class Solution { public static boolean canFinish() { System.out.println("here"); return true; } public static void main(String[] args) { ((Solution) null).canFinish(); } } 運行得到正確調用結果: here
說明,用null是可以調用 static 方法的。