1. 程式人生 > >Java謎題暢讀版之字元謎題

Java謎題暢讀版之字元謎題

謎題11:最後的笑聲

public class LastLaugh{
    public static void main(String[] args){
        System.out.print("H"+"a");
        System.out.print('H'+'a');
    }
}
你期待程式打出HaHa, 但是不是。
問題的關鍵在於:char的本質是16位無符號整數。所以結果它列印的是它列印的是Ha169.

謎題12:ABC

先看第一個:
public class NumberTest{
    public static void main(String[] args){
        char[] numbers = {'1', '2', '3'};
        System.out.println(numbers);
    }
}
它列印的是123.
那麼
public class ABC{
    public static void main(String[] args){
        String letters = "ABC";
        char[] numbers = {'1', '2', '3'};
        System.out.println(letters + " easy as " + numbers);
    }
}
會輸出什麼?
雖然char本質是16位整數,很多庫方法對char做了特殊處理, 比如println會輸出char的unicode字元,println字元陣列會打印出所有的字元. String.valueOf和StringBuffer.append的char[]過載版本的行為也是類似的.
然而字元相加卻會呼叫字元陣列的toString函式,所以結果會打印出ABC easy as [
[email protected]
一樣的東西。

謎題13:畜牧場

這個程式會列印Animals are equal: true嗎?
public class AnimalFarm{
    public static void main(String[] args){
        final String pig = "length: 10";
        final String dog = "length: " + pig.length();
        System.out. println("Animals are equal: "
                            + pig == dog);
    }
}
這個程式有兩個問題, 它只打印出false, 你應該能知道第一個問題出現在哪裡。它相當於System.out.println(("Animals are equal: " + pig) == dog);
如果你把改成System.out.println("Animals are equal: " + (pig == dog)); 然後你想到了intern, 但是你執行程式, 並沒有像你想的那樣打印出Animals are equal: true.
String型別的變數,如果是通過字面量直接賦值,則相同的字面量共享一個copy;如果有+運算,比如"a"+"b",或者a+1,a+true,即String和原始型別的字面量直接相加,則在編譯器直接把+運算做掉;如果是String加上一個變數,則不會在編譯期優化;如果是String+Final變數,則在編譯器就進行優化。如果是String+函式呼叫,則不會在編譯期優化。
關於string常量表達式的處理和優化, 可以看看這裡:www.blogjava.net/aoxj/archive/2009/11/10/165536.html

謎題14:轉義字元的潰敗

public class EscapeRout{
    public static void main(String[] args){
        // \u0022 是雙引號的Unicode轉義字元
        System.out.println("a\u0022.length()+\u0022b".length());
    }
}
會不會輸出26?因為a\u0022.length()+\u0022b總共有26個字元? 你會說不對, 因為\u連同後面的4個字元是一個unicode字元。所以應該是16.
程式會輸出2.
記住一點: 編譯器對unicode的解析優先於對符號的解析。所以程式等同於:System.out.println("a".length()+"b".length());

謎題15:令人暈頭轉向的Hello

/**
 * Generated by the IBM IDL-to-Java compiler, version 1.0
 * from F:\TestRoot\apps\a1\units\include\PolicyHome.idl
 * Wednesday, June 17, 1998 6:44:40 o’clock AM GMT+00:00
 */
public class Test{
    public static void main(String[] args){
        System.out.print("Hell");
        System.out.println("o world");
    }
}
這個程式輸出什麼? 如果你執行一下, 你會發現它不能通過編譯。
問題處在\units。\u表示unicode的開始,後面緊跟4位16進位制的數字。
所以如同14裡面說的,編譯器對unicode的解析優先於對符號的解析,哪怕是在註釋中。

謎題16:行列印程式

public class LinePrinter{
    public static void main(String[] args){
    // Note: \u000A is Unicode representation of linefeed (LF)
        char c = 0x000A;
        System.out.println(c);   
    }
}
同樣這個程式不能通過編譯,原因就不說了, 如果14 15你懂了, 這個你也懂的。

謎題17:嗯?

下面的是一個合法的Java程式嗎?
\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020\u0020
\u0063\u006c\u0061\u0073\u0073\u0020\u0055\u0067\u006c\u0079
\u007b\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020
\u0020\u0020\u0020\u0020\u0073\u0074\u0061\u0074\u0069\u0063
\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028
\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0020
\u0020\u0020\u0020\u0020\u0061\u0072\u0067\u0073\u0029\u007b
\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074
\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0020
\u0022\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u0022\u002b
\u0022\u006f\u0072\u006c\u0064\u0022\u0029\u003b\u007d\u007d
這個當然是合法的java程式。可以用javascript alert一下上面的字串,即可得看到廬山真面目。對於這個題目,我思考的是,如何用java把它還原, Integer.parseInt可以做這個事情, 比如(char)Integer.parseInt("006F", 16) =='o; 反向轉換更簡單,比如我有char c = '啊'; 我想獲得c的unicode形式, 則Integer.toString((int)c, 16);

謎題18:字串乳酪

程式打印出什麼?
public class StringCheese {
    public static void main(String[] args) {
        byte bytes[] = new byte[256];
        for (int i = 0; i < 256; i++)
             bytes[i] = (byte)i;
        String str = new String(bytes);
        for (int i = 0, n = str.length(); i < n; i++)
             System.out.println((int)str.charAt(i) + " ");
    }
}
乍看, 會打印出0~255,在我機器上一執行, 會發現,0~127可以正常打印出來,後面的都是65533。
問題出在String str = new String(bytes); 當你用位元組陣列構造String的時候, 應該考慮編碼問題,即程式使用什麼編碼來解析字元陣列從而構造出String。如果你String str = new String(bytes, "iso-8859-1");則能夠打印出0~255。在這裡我感興趣的是為什麼127之後都出現的是65533。
我通過System.out.println(Charset.defaultCharset().name());得知我的機器的預設字符集是utf-8,對utf-8稍微瞭解的就知道,utf-8的字元的位元組數是可變長的,如果一個byte的最高位是0, 則認為該位元組是是一個單位元組字元,也即和ascii部分是一致的。所以對於本例, 0~127滿足utf-8單位元組字元的要求, 可以被正確識別。但是如果最高位不是0, 則需要滿足更多的規則,比如,兩個位元組的utf8的二進位制應該滿足110xxxxx 10xxxxxx. 三個位元組的應該滿足1110xxxx 10xxxxxx 10xxxxxx。如果不滿足這些規則,則會用65533代替該字元,表示它無法識別, 建議閱讀http://blog.csdn.net/sfdev/article/details/3770706.

謎題19:漂亮的火花 - 塊註釋符

下面的程式用一個方法對字元進行了分類,區分他們是letter還是operator。這個程式會打印出什麼呢?
public class Classifier {
    public static void main(String[] args) {
        System.out.println(
             classify('n') + classify('+') + classify('2'));
    }
    static String classify(char ch) {
        if ("0123456789".indexOf(ch) >= 0)
             return "NUMERAL ";
        if ("abcdefghijklmnopqrstuvwxyz".indexOf(ch) >= 0)
             return "LETTER ";
        /* (Operators not supported yet)
            if ("+-*/&|!=" >= 0)
                 return "OPERATOR ";
        */
        return "UNKNOWN";
    }
}
只需要你把它拷貝到eclipse,就會發現它無法編譯。
問題在於*/破壞了註釋的結構。
另外需要注意的是:塊註釋不能巢狀。所以下面的程式碼也不能通過編譯。
/*
/* Add the numbers from 1 to n */
int sum = 0;
for (int i = 1; I <= n; i++)
sum += i;
*/

謎題20:我的類是什麼?

你期待下面的程式打印出類路徑,以/分割包名。
public class Me {
    public static void main(String[] args){
        System.out.println(
             Me.class.getName().
                replaceAll(".","/") + ".class");
    }
}
實際上他打印出///////////////////.class。
問題在於String.replaceAll接受了一個正則表示式作為它的第一個引數,而"."可以匹配任何單字元。
解決方法如下:
public class Me {
    public static void main(String[] args){
        System.out.println(
            Me.class.getName().replaceAll("\\.","/") + ".class");
    }
}

謎題21:我的類是什麼?II

import java.io.File;
public class MeToo {
    public static void main(String[] args){
        System.out.println(MeToo.class.getName().
            replaceAll("\\.", File.separator) + ".class");
    }
}
這個程式的錯誤和平臺相關, 你能看出來嗎?
如果你在windows下執行, replaceAll("\\.", File.separator)這句話就相當於:replaceAll("\\.", "\\").

謎題22:URL的愚弄

public class BrowserTest {
    public static void main(String[] args) {
        System.out.print("iexplore:");
        http://www.google.com;
        System.out.println(":maximize");
        
    }
}
這個程式有錯嗎?乍一看覺得肯定不能通過編譯,事實上它可以執行。但是這個特性很少被用到. http:定義了一個label,這個label可以用來在多重迴圈的情況下break用的。後面的//www.google.com;是一個普通註釋

謎題23:不勞無獲

import java.util.Random;
public class Rhymes {
   private static Random rnd = new Random();
   public static void main(String[] args) {
      StringBuffer word = null;
      switch(rnd.nextInt(2)) {
          case 1:  word = new StringBuffer('P');
          case 2:  word = new StringBuffer('G');
          default: word = new StringBuffer('M');
      }
      word.append('a');
      word.append('i');
      word.append('n');
      System.out.println(word);
   }
}
這個程式有3個問題, 你能看出幾個?
問題1 rnd.nextInt(2)的取值範圍為(0,1),而switch語句裡面的卻是case 1, case 2;
問題2 new StringBuffer('M')裡面的引數是char,而char的本質是16位無符號整數,此時這個引數代表了該buffer初始長度;
問題3 case語句沒有break, 所以就算你把程式修改成下面的樣子,它只會輸出Main, 原因不解釋。
public class Rhymes {
    private static Random rnd = new Random();
    public static void main(String[] args) {
        StringBuffer word = null;
        switch(rnd.nextInt(2)) {
            case 0: word = new StringBuffer("P");
            case 1: word = new StringBuffer("G");
            default: word = new StringBuffer("M");
        }
        word.append('a');
        word.append('i');
        word.append('n');
        System.out.println(word);
    }
}





相關推薦

Java字元

謎題11:最後的笑聲 public class LastLaugh{ public static void main(String[] args){ System.out.print("H"+"a"); System.out.prin

Java表示式

謎題1:奇數性 下面判斷一個數是否是奇數,這個程式對嗎?public static boolean isOdd(int i){ return i % 2 == 1; }這裡需要注意的是負奇數,負奇數i%2 = -1; 正確的程式可以如下:public static

Java

謎題56:大問題 我們來測試一下你對BigInteger的瞭解程度。下面這個程式將打印出什麼呢? import java.math.BigInteger; public class BigProblem { public static void main(Strin

Java程式設計思想(第4) 15.5 泛型匿名內部類

15.5   匿名內部類 泛型還可以應用於內部類以及匿名內部類。下面的示例使用匿名內部類實現了Generator介面:     Customer和Teller類都只有private的構造器,這可以強制你必須使用Generator物件。Customer有一個generator(

JAVA輸入輸出(IO)字元

上一篇《JAVA輸入輸出(IO)之位元組流》介紹了JAVA位元組輸入輸出流的一些用法,位元組流一般是用於讀寫二進位制資料的,當我們要讀些字元資料的時候,如文字檔案,就顯得有些麻煩。所以JAVA還提供了專門用於讀寫字元資料的字元流。 字元輸入流 java.

劍指Offer每日六(JAVA)第二天

斐波那契數列 跳臺階 變態跳臺階 矩形覆蓋 二進位制中1的個數 數值的整數次方 斐波那契數列: 大家都知道斐波那契數列,現在要求輸入一個整數n,請你輸出斐波那契數列的第n項(從0開始,第0項為0)。 n<=39 解答: 這個是一個最簡單的斐波那契題目,斐

Java解惑》系列——02字元——14:轉義字元的潰敗

謎題14至17,講的都是用16進位制程式碼表示unicode字元導致的問題。 知識點: Java對在字串字面常量中的Unicode轉義字元(16進製表示)沒有提供任何特殊處理。 編譯器在將程式解析成各種符號之前,先將Unicode轉義字元轉換成為它們所表示的字元[JLS

玩玩微信公眾號Java二:接收、處理及返回微信消息

log med iou set arch weixin b- rom data- 前面已經配置了微信服務器,那麽先開始最簡單的接收微信消息吧~ 可以用我們的微信號來直接進行測試,下面先看測試效果圖: 這是最基本的文本消息的接收、處理及返回,來看看是怎麽實現的

數據結構Java遍歷二叉樹(六)

val unit 說明 後續遍歷 auth AD oot org tor   二叉樹是我們在程序中用的最多的一種樹(個人觀點)。最簡單的一個二叉樹是由一個根節點,兩個子節點(一左一右成左右孩子節點)組成。二叉樹是數組和鏈表的結合,即包含了數組的快速查找優點,又包含了鏈表的快

數據結構Java紅黑樹(八)

如何 當前 鏈接 根節點 java版 -- 查找 變色 繼承   紅黑樹是一種自動平衡的二叉查找樹,因為存在紅黑規則,所以有效的防止了二叉樹退化成了鏈表,且查找和刪除的速度都很快,時間復雜度為log(n)。   什麽是紅黑規則?   1.根節點必須是黑色的。   2.節點顏

數據結構Java深度優先-圖(十二)

pac show 下標 增加 ava style AD amp mat 這裏用深度優先遍歷存在矩陣裏面的圖。   深度優先利用的是棧的FIFO特性。為此遍歷到底後,可以找到最相鄰的節點繼續遍歷。實現深度優先,還需要在節點加上一個訪問標識,來確定該節點是否已經被訪問過了。 源

數據結構Java堆&堆排序(九)

add lse spa led main AD 節點 之間 ren   堆分為大頂堆,和小頂堆。 什麽是堆? 堆可以看成是一棵二叉樹,二叉樹的元素是一個數組不斷的從左到右輪訓放置。如果是大頂堆,則大的數放上面一層,小的數放下面一層。上一層的數,一定大於下一層的數。小頂堆則相

資料結構JAVA棧和佇列

一、涉及的內容大綱 二、簡單介紹棧、佇列和其他資料結構的不同 1 對於其他的資料結構而言,都適用與資料庫應用中作資料記錄。但是因為棧和佇列的生命週期比那些資料庫型別的資料結構要短,所以他們只是在程式的操作期間才會建立和執行,在完成任務之後就會被銷燬。所以棧和佇列更多的是用於構思演算法的

Java 解惑》 第二章 表示式

簡述: 《Java 解惑》  第二章 表示式之謎 謎題1:奇數性 package com.anialy.test.java_puzzlers.chapter_1; public class 奇數性 { public static void mai

Java基礎字元常量

       表示一個字元,一個字元常量要用一對英文半形格式的單引號(' ')引起來,它可以是英文字母、數字、標點符號、以及由轉義序列來表示的特殊字元。 'a' '1' '&' '\r' '\u0000'      

22 Java學習字元流(Reader和Writer)

  Java中的流是個抽象的概念,當程式需要從某個資料來源讀入資料的時候,就會開啟一個數據流,資料來源可以是檔案、記憶體或網路等等。相反地,需要寫出資料到某個資料來源目的地的時候,也會開啟一個數據流,這個資料來源目的地也可以是檔案、記憶體或網路等等 一. 字元流的引入 正如位元組流中所

java筆記IO流(二)字元

字元流是什麼     * 字元流是可以直接讀寫字元的IO流     * 字元流讀取字元, 就要先讀取到位元組資料, 然後轉為字元. 如果要寫出字元, 需要把字元轉為位元組再寫出. //標準使用方法 public stati

Java IO流字元

1.字元輸出流 Writer(只能寫入文字檔案) 1.1FileWriter類(writer的子類) 構造方法: public class FileWriterDemo { public static void main(String[] args) throws IOE

《ThinkinginJavathEdition(JAVA程式設計思想 第四 英文版)》pdf附網盤下載連結+(附一個菜鳥的java學習路)

技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好的作用。 對於每一章的知識,先閱讀標題,弄懂大概講的是什麼主題,再去快速看一遍,不懂也沒有關係,但是一定要在不懂的

java:集合框架(泛型高階萬用字元)

* A:泛型萬用字元<?>     * 任意型別,如果沒有明確,那麼就是Object以及任意的Java類了 * B:? extends E     * 向下限定,E及其子類 * C:? su