Java五道輸出易錯題解析(避免小錯誤)

收集了幾個易錯的或好玩的Java輸出題,分享給你們,之後在編程學習中稍微注意下就OK了。java

1. 看不見的空格?

下面的輸出會正常嗎?編程

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));

 

2. 類靜態成員初始化

下面的程序能編譯經過麼?若是經過,說結果並解釋,不能編譯,說錯誤緣由。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

 

3. 裝箱拆箱的實際過程

關於自動裝箱,相信大部分人都明白是怎麼一回事,但真的徹底明白了嘛?
先看下面的代碼: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);


哦,原來如此,這下明白了,所以咱們在使用自動裝箱的時候當心點爲妙。

 

4. 你自覺得是的異常

先來兩句代碼:

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(),但誰不不能保證不會碰到這樣的代碼,所以仍是當心爲妙。

 

5. 變長參數和數組,如何變通?

變長參數特性帶來了一個強大的概念,能夠幫助開發者簡化代碼。不過變長參數的背後是什麼呢?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) { … }

 

參考資料

相關文章
相關標籤/搜索