Java Puzzlers 小噺 No.11
概要
Java Puzzlers[1][2] という本で面白い問題を見つけて、Java の仕様を改めて調べてみたという感じの記事です。
この記事では、「Puzzle 11: The Last Laugh」を取り上げます。
きっかけ
たまたま、図書館で見かけて、読んだら面白く、社内の LT 会でこの問題とその仕様についての話をしてみたら、ウケが良かったので、記事にしました。
本題
「Puzzle 11 : The Last Laugh」は以下のソースコードです。[4]
public class LastLaugh {
public static void main(String args[]) {
System.out.print("H" + "a");
System.out.print('H' + 'a');
}
}
とくに考えなければ、
Ha
Ha
と出そうですが、実際は、
Ha
169
と出ます。
(☉ε ⊙ノ)ノ「え、嘘!」
( ゚Д゚)「なんで!」
と思った方は、ぜひそのまま読み進めてください。
ε- (´ー`*)「フッ、そんなの当たり前じゃん」
(´-_ゝ-`)「なぜわからないのかわからない」
などと思った方は、リンク元にお戻りいただくか、このタブをそっ閉じしてください。
解説
結論を先に述べると以下の2点です。
- プリミティブ型
char
の値の実体は整数値 -
String
とchar
における+
の扱い方の違い
それぞれ、説明していきます。
char
の値の実体は整数値
プリミティブ型 Java において、char
の実体は 16 ビット符号なし整数です。[5]
なので、整数値でいうと、0 から 65535 までの値を保持できます。
ここで言いたいこととしては、横柄な言い方をすると、
char
はシングルクォーテーションで囲って定義するので文字に見えるけど、実質は整数値だということです。
今回のコード上の H
と a
はそれぞれ ASCII コードで整数に表現すると 72
と 97
となります。
String
と char
における +
の扱い方の違い
String
型においての +
は文字列連結として働きますが、
char
型における +
は文字連結ではなく、足し算として働きます。
なので、冒頭の結果の通り、'H' + 'a'
は 72 + 97
となり、169
と表示されることになります。
チョットだけ発展
ここで、更に考えると String
と char
とを +
で結ぶとどうなるかということです。
結論は、先の参考リンク先に書かれている通りです。
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.
(和訳)
もし1つのオペランド式がString
型の場合、もう一方のオペランドに対して実行時に文字列変換(§5.1.11)が行われ、文字列が生成されます。
要は、+
を挟むどちらかが、String
型であれば、もう片方は対応する文字列変換[6]がされて、その 2 つの文字列連結になるということです。
具体的には、String + char
や char + String
の場合は、char
は単純に文字列に変換されたのちに、文字連結されます。
System.out.print("H" + 'a'); // Ha
System.out.print('H' + "a"); // Ha
また、評価順を考えると、String + char + char
と char + char + String
では結果が変わります。
System.out.print("Ha" + 'H' + 'a'); // HaHa
System.out.print('H' + 'a' + "Ha"); // 169Ha
これも、ここまで読まれていれば理由はわかると思いますが、最初の 2 項の評価結果がそれぞれ違うからですね。
要は、最初の 2 項を評価しますので、それぞれ "Ha" + 'H'
は文字列 "HaH"
となり、'H' + 'a'
は数値 169
となる。
その後、3 項目の評価になるので、それぞれ "HaH" + 'a'
、169 + "Ha"
となる。そして、上記のコメントのところの文字列が表示される流れです。
さいごに
今回の問題を考えることで、Java におけるプリミティブ型の仕様と演算子 +
の仕様について再認識できました。
とはいえ、実務で char
を使う機会は少ないと思いますので、この記事自体がすぐに役に立つことは難しいかもしれませんが、 Java 言語仕様に関して興味を持ってもらえれば嬉しいなと思っています。
参考リンク
- Java Puzzlers の公式ページ
- Java Language Specifications
参考文献
- Joshua Bloch & Neal Gafter (2005). Java puzzlers traps, pitfalls, and corner cases Addison-Wesley Professional. (ジョシュア・ブロック ニール・ガフター 柴田 芳樹 (2005). Java Puzzlers 罠、落とし穴、コーナーケース 桐原書店)
-
参考文献にも書いていますが、原著は 2005 年に Joshua Bloch 氏と Neal Gafter 氏によって書かれ、同年に柴田 芳樹氏による翻訳も桐原書店より出版されました。 ↩︎
-
もっというと、翻訳本はもともとピアソン・エデュケーション時代に出版されていました。その後、ピアソン桐原時代があったりして、現在は絶版になっています。出版年からでもお察しいただける通り、Java は J2SE 5.0 時代なので、そのあたりを考えるとなんか感慨深いです。 ↩︎
-
時間があれば程度ですね。 ↩︎
-
ソースコードは公式で公開されています。詳細は参考リンクの書籍公式ページ内のリンクをご確認ください。 ↩︎
-
そもそもでいうと、
char
は Unicode(UTF-16) を表すからですね。 ↩︎ -
詳細は文字列変換についてを参考してください。簡単に言うと、プリミティブ型はそれに相当するラッパークラスにオートボックスしてから、
toString()
で文字列に変換されます。 ↩︎
私たち BABY JOB は、子育てを取り巻く社会のあり方を変え、「すべての人が子育てを楽しいと思える社会」の実現を目指すスタートアップ企業です。圧倒的なぬくもりと当事者意識をもって、子どもと向き合う時間、そして心のゆとりが生まれるサービスを創出します。baby-job.co.jp/
Discussion