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
先看第一個:它列印的是123.public class NumberTest{ public static void main(String[] args){ char[] numbers = {'1', '2', '3'}; System.out.println(numbers); } }
那麼
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 [
謎題13:畜牧場
這個程式會列印Animals are equal: true嗎?這個程式有兩個問題, 它只打印出false, 你應該能知道第一個問題出現在哪裡。它相當於System.out.println(("Animals are equal: " + pig) == dog);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); } }
如果你把改成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