開始徹底一頭霧水呀,後面看了Java指令集的介紹,逐漸理解了。html
https://www.zhihu.com/question/21574535/answer/18998914java
下面這個答案比較直白面試
你在面月薪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
上面指令的定義詳細解釋以下(解釋和重要點已經飄紅指出):oracle
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.component
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 方法的。