1 public class Main { 2 public void test(Object o) { 3 System.out.println("Object"); 4 } 5 public void test(String s) { 6 System.out.println("String"); 7 } 8 public static void main(String[] args) { 9 Main that = new Main(); 10 that.test(null); 11 } 12 }
請寫出運行輸出
String
這個考的是Java的method overload resolution。根據Java語言規范的規定:
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
這里的that.test(null)可以匹配上兩個重載版本的test()方法,但是String版本比Object版本更具體,所以匹配上String版。
如果此處要強制選擇Object版,則可以寫:that.test((Object) null);
1. 以下程序運行時是否會拋出異常, 以及程序輸出.
1 public class a { 2 static String s0, s1; 3 public static void main(String args[]) { 4 s0 = s0 + s1; 5 System.out.println(s0); 6 } 7 }
這個考察的是靜態變量的默認初始化,以及String的連接(+)。
靜態變量會在類加載過程中的linking階段得到默認初始化。引用類型的靜態變量會被默認初始化為null。
然后是String對象的連接。根據Java語言規范:
15.18.1. String Concatenation Operator +
If only one operand expression is of type String, then string conversion (
§5.1.11) is performed on the other operand to produce a string at run time.
The result of string concatenation is a reference to a String object that is the concatenation of the two operand strings. The characters of the left-hand operand precede the characters of the right-hand operand in the newly created string.
The String object is newly created (
§12.5) unless the expression is a constant expression (
§15.28).
然后對null的情況規范也做了規定:
The operators on references to objects are:
- ...
- The string concatenation operator + (§15.18.1), which, when given a String operand and a reference, will convert the reference to a String by invoking the toString method of the referenced object (using "null" if either the reference or the result of toString is a null reference), and then will produce a newly created String that is the concatenation of the two strings
(抱歉之前我寫這個回答的時候看漏了這規范的這部分。對null的規定居然跟string concat運算符的規定沒寫在一起…)
如果考慮Sun JDK 1.0 - 1.4.2的實現的話,s0 = s0 + s1;是一個語法糖,會被解糖為:
s0 = new StringBuffer().append(s0).append(s1).toString();
考慮Oracle/Sun JDK 5、6、7、8的實現的話,則會被解糖為:
s0 = new StringBuilder().append(s0).append(s1).toString();
根據規范,此處調用的StringBuffer / StringBuilder.append(String)方法會對null做特殊處理,把它當作"null"字符串。相關實現:
jdk8u/jdk8u/jdk: 3dc438e0c8e1 src/share/classes/java/lang/AbstractStringBuilder.java
所以最后答案是"nullnull"。
(注意:Oracle/Sun JDK 9改變了String +的實現,解除語法糖后不再是對StringBuilder的調用了。可以參考
JEP 280: Indify String Concatenation。但用戶代碼能觀察到的行為不變,結果仍然是"nullnull"。)
2.寫出 `WindowAdapter.windowClosing, ActionListener.actionPerformed` 方法的參數類型.
3.下列程序的輸出:
1 // ... 2 public static void main(String args[]) { 3 String a = "abc"; 4 String b = "ab" + "c"; 5 System.out.println(a == b); 6 // ... 7 }
public class Test { public static void main(String args[]) { String a = "abc"; String b = "ab" + "c"; System.out.println(a == b); } }

這個考察的是Java的編譯時常量、編譯時常量折疊,以及String interning的知識。
"abc"、"ab"、"c"在Java里都是String類型的編譯時常量。當+運算符的左右兩個操作數都是編譯時常量時,這個+表達式也會被認為是編譯時常量表達式。
再看Java語言規范:
15.28. Constant Expressions
A constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:
- Literals of primitive type and literals of type String (§3.10.1, §3.10.2, §3.10.3,§3.10.4, §3.10.5)
- …
- The additive operators + and - (§15.18)
- …
Constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern.
以及:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (
§15.28) - are "interned" so as to share unique instances, using the method String.intern.
String.intern的文檔:
public String intern()
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the
equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.
All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java™ Language Specification.
Returns:a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.
換句話說,上述代碼等價於:
// ... public static void main(String args[]) { String a = "abc"; String b = "abc"; System.out.println(a == b); // ... }
結果就顯而易見了。內容相同的String類型編譯時常量會被intern為同一個對象,所以a與b都引用了這個對象,要檢查它們是否引用相等,自然得到true。
作者:RednaxelaFX
鏈接:https://www.zhihu.com/question/50111592/answer/119694222
來源:知乎
附語,不會查詢API,好像查了也得靠有道來看。。嗚嗚~加油~要看懂!!