收集了幾個易錯的或好玩的Java輸出題,分享給你們,之後在編程學習中稍微注意下就OK了。java
下面的輸出會正常嗎?編程
package basic;
public class IntegerTest {
public static void main(String[] args) {
System.out.println(Integer.parseInt("1"));
System.out.println(Integer.parseInt("2"));
}
}
解析:將上面代碼複製下(不要本身手敲)在本身的環境裏運行看看,是否是輸出下面錯誤來了:vim
1
Exception in thread 「main」 java.lang.NumberFormatException: For input string: 「2」
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at basic.IntegerTest.main(IntegerTest.java:7)數組
居然說第二條語句有問題,表面上徹底看不出來任何問題是否是!
實際上這裏的錯誤緣由涉及到一個概念 — 零寬度空格,可能有人接觸過,但相信更多的人甚至都沒聽過,什麼是零寬度空格?它實際上是一個Unicode字符,是一個空格,關鍵是它沒有寬度,所以咱們通常肉眼看不到。但能夠在vim下看到,上面的第二條語句中的2前面就有一個零寬度空格,放到vim中打開後你會發現是下面這樣的語句:學習
System.out.println(Integer.parseInt("<feff>2"));
Unicode規範中定義,每個文件的最前面分別加入一個表示編碼順序的字符,這個字符的名字叫作」零寬度非換行空格「(ZEROWIDTHNO-BREAKSPACE),用FEFF
表示。這正好是兩個字節,並且FF比FE大1。所以下面的語句會輸出65279,恰好是FEFF
。編碼
System.out.println((int)"2".charAt(0));
下面的程序能編譯經過麼?若是經過,說結果並解釋,不能編譯,說錯誤緣由。spa
class A
{
public static int X;
static { X = B.Y + 1;}
}
public class B
{
public static int Y = A.X + 1;
static {}
public static void main(String[] args) {
System.out.println("X = "+A.X+", Y = "+B.Y);
}
}
解析:這個程序能正確運行,類的運行過程以下:翻譯
首先加載主類B,初始化靜態成員Y,發現須要類A的信息,因而加載類A,初始化靜態成員X,也用到B類信息,因爲此時B類的Y還未成功加載所以這裏是默認值0,從而獲得A類的X爲1,而後返回到B類,獲得Y爲2。code
關於自動裝箱,相信大部分人都明白是怎麼一回事,但真的徹底明白了嘛?
先看下面的代碼:orm
Short s1 = 1;
Short s2 = s1;
System.out.println(s1 == s2);
誰都知道固然打印true了。如今加一句試試:
Short s1 = 1;
Short s2 = s1;
s1++;
System.out.println(s1 == s2);
仍是true嗎?No,此次輸出成了false。WHY?難道s1和s2引用的不是同一個對象嗎?有這些疑問的說明你對自動裝箱拆箱的過程還不是很是清楚,實際上上面的代碼能夠翻譯爲下面的代碼(實際執行過程,要掌握):
Short s1 = new Short((short)1);
Short s2 = s1;
short tempS1 = s1.shortValue();
tempS1++;
s1 = new Short(tempS1);
System.out.println(s1 == s2);
哦,原來如此,這下明白了,所以咱們在使用自動裝箱的時候當心點爲妙。
先來兩句代碼:
NullTest myNullTest = null;
System.out.println(myNullTest.getInt());
相信不少人看到這段代碼時,都會自覺得是的說:NullPointerException
。果然如此嗎?你還沒看到NullTest 這個類是如何定義的呢。如今看看這個類的定義:
class NullTest {
public static int getInt() {
return 1;
}
}
發現getInt()
方法體沒有任何類變量和類方法的使用,所以這裏會正常輸出1.
記住:類變量和類方法的使用,僅僅依賴引用的類型。即便引用爲null,仍然能夠調用。從良好實踐的角度來看,明智的作法是使用NullTest.getInt()
來代替myNullTest.getInt()
,但誰不不能保證不會碰到這樣的代碼,所以仍是當心爲妙。
變長參數特性帶來了一個強大的概念,能夠幫助開發者簡化代碼。不過變長參數的背後是什麼呢?Basically,就是一個數組。
public void calc(int... myInts) {}
calc(1, 2, 3);
編譯器會將前面的代碼翻譯成相似這樣:
int[] ints = {1, 2, 3};
calc(ints);
不過這裏有兩點須要注意:
- 小心空調用語句,這至關於傳遞了一個null做爲參數。
calc();
等價於
int[] ints = null;
calc(ints);
- 固然,下面的代碼會致使編譯錯誤,由於兩條語句是等價的:
public void m1(int[] myInts) { … }
public void m1(int… myInts) { … }