Java puzzlers 2013 at JavaFesta Japan

54
ꜳꜳ Ꜳꜳ ꝏff ꝃÌꝏ 櫻庭 祐一 寺田 佳央

Transcript of Java puzzlers 2013 at JavaFesta Japan

Page 1: Java puzzlers 2013 at JavaFesta Japan

JJaavvaa PPuuzzzzlleerrss AAttttaacckk ooff tthhee OObbjjeecctt##CClloonnee

櫻庭 祐一 寺田 佳央

Page 2: Java puzzlers 2013 at JavaFesta Japan

コード中に発生する勘違い

�  JJaavvaa プログラミングのパズル � 奇妙な振る舞いをする小さなプログラム � 複数の選択肢から、何が表示される? � ミステリーの解明 � 問題の解決方法 � 教訓

Page 3: Java puzzlers 2013 at JavaFesta Japan

ルール:全て4択です

public class JavaPuzzlers {   public static void main(String... args) { "    http://www.java-users.jp   "    System.out.println(“Japan Java User Group Presents!”); } " } "

11))  JJaappaann JJaavvaa UUsseerrss GGrroouupp PPrreesseennttss!! 22))  JJaavvaa PPuuzzzzlleerrss 33))  00xxccaaffeebbaabbee 44))  その他 全員参加です

Page 4: Java puzzlers 2013 at JavaFesta Japan

11 問目

Page 5: Java puzzlers 2013 at JavaFesta Japan

1.. FFiinnddRRoooottss class Ancestor {" String name = "祖先”;" String getName() {return name;}"}"class Descendant extends Ancestor {" String name = "子孫";" @Override" String getName() {return name;}"}""public class FindRoots {" public static void main(String argv[]) {" Ancestor person = new Descendant();" System.out.println(" person.name + ":" + person.getName());" }"}"

1)  祖先:祖先2)  ⼦子孫:⼦子孫3)  祖先:⼦子孫4)  ⼦子孫:祖先

Page 6: Java puzzlers 2013 at JavaFesta Japan

正解は

Page 7: Java puzzlers 2013 at JavaFesta Japan

class Ancestor {" String name = "祖先”;" String getName() {return name;}"}"class Descendant extends Ancestor {" String name = "子孫";" @Override" String getName() {return name;}"}""public class FindRoots {" public static void main(String argv[]) {" Ancestor person = new Descendant();" System.out.println(" person.name + ":" + person.getName());" }"}"

1.. FFiinnddRRoooottss

3)  祖先:⼦子孫

Page 8: Java puzzlers 2013 at JavaFesta Japan

�  フィールドはコンパイル時に親クラスの情報を引き継ぎます �  メソッドは実行時に上書きしたメソッドを呼び出します �  仮にどうしても子のフィールドにアクセスしたい場合、   キャストして取得します

11.解説

Page 9: Java puzzlers 2013 at JavaFesta Japan

class Ancestor {" String name = "祖先”;" String getName() {return name;}"}"class Descendant extends Ancestor {" String name = "子孫";" @Override" String getName() {return name;}"}""public class FindRoots {" public static void main(String argv[]) {" Ancestor person = new Descendant();" System.out.println(" ((Descendant)person).name + ":" + person.getName());" }"}"

1.. 解決方法

3)  祖先:⼦子孫

Page 10: Java puzzlers 2013 at JavaFesta Japan

�  フィールドは隠蔽し直接アクセスしないようにしてください

1.教訓

Page 11: Java puzzlers 2013 at JavaFesta Japan

22 問目

Page 12: Java puzzlers 2013 at JavaFesta Japan

public class MajorityVote {" public static void main(String... args) {"   Random[] randoms = new Random[10];"    for (int i = 0; i < 10; i++)"     randoms[i] = new Random(System.currentTimeMillis());"" int count = 0;"    boolean option = randoms[0].nextBoolean();"    for (int i = 1; i < 10; i++)"      if (option == randoms[i].nextBoolean()) count++;""    System.out.println((count > 5)? "YES": "NO");"  }"}"

22.MMaajjoorriittyyVVoottee 11))  YYEESS 22))  NNOO 33)) 場合による 44)) tthhrrooww EExxcceeppttiioonn

Page 13: Java puzzlers 2013 at JavaFesta Japan

正解は

Page 14: Java puzzlers 2013 at JavaFesta Japan

public class MajorityVote {" public static void main(String... args) {"   Random[] randoms = new Random[10];"    for (int i = 0; i < 10; i++)"     randoms[i] = new Random(System.currentTimeMillis());"" int count = 0;"    boolean option = randoms[0].nextBoolean();"    for (int i = 1; i < 10; i++)"      if (option == randoms[i].nextBoolean()) count++;""    System.out.println((count > 5)? "YES": "NO");"  }"}"

22.MMaajjoorriittyyVVoottee 11))  YYEESS

Page 15: Java puzzlers 2013 at JavaFesta Japan

�  RRaannddoommのコンストラクタは、乱数シードを指定します

�  ループは11 ミリ秒の間に処理が完了します → 乱数シードが全て同一となります

�  デフォルトコンスタクタはSSyysstteemm..nnaannooTTiimmee(())を使用  します

22.解説

Page 16: Java puzzlers 2013 at JavaFesta Japan

public class MajorityVote {" public static void main(String... args) {"   Random[] randoms = new Random[10];"    for (int i = 0; i < 10; i++)"     randoms[i] = new Random();"" int count = 0;"    boolean option = randoms[0].nextBoolean();"    for (int i = 1; i < 10; i++)"      if (option == randoms[i].nextBoolean()) count++;""    System.out.println((count > 5)? "YES": "NO");"  }"}"

22.. 解決方法

Page 17: Java puzzlers 2013 at JavaFesta Japan

�  デフォルトのコンストラクタを使用してください

�  テスト時など乱数系列をあえて同一にするテクニックもあります

22.教訓

Page 18: Java puzzlers 2013 at JavaFesta Japan

33 問目

Page 19: Java puzzlers 2013 at JavaFesta Japan

public class CutAndPaste{ public static void main(String... argv) {"

   String firstLine = "1,2,3";   String secondLine = "4,5,6";    List<String> firstList = "

Arrays.asList(firstLine.split(”,"));   List<String> secondList = "

Arrays.asList(secondLine.split(”,"));    firstList.addAll(secondList);    for(String data : firstList){   System.out.print(data);    }   } }"

33.CCuuttAAnnddPPaassttee 11)) 112233 22)) 112233445566 33)) コンパイル・エラー 44)) ランタイム・エラー

Page 20: Java puzzlers 2013 at JavaFesta Japan

正解は

Page 21: Java puzzlers 2013 at JavaFesta Japan

public class CutAndPaste { public static void main(String argv[]){"   String firstLine = "1,2,3";   String secondLine = "4,5,6";    List<String> firstList = "

"Arrays.asList(firstLine.split("\\,"));   List<String> secondList ="

"Arrays.asList(secondLine.split("\\,"));    firstList.addAll(secondList);    for(String data : firstList){   System.out.print(data);    }   } }"

33.CCuuttAAnnddPPaassttee 44)) ランタイム・エラー

UUnnssuuppppoorrtteeddOOppeerraattiioonnEExxcceeppttiioonn を送出

Page 22: Java puzzlers 2013 at JavaFesta Japan

�  AArrrraayyss..aassLLiisstt は固定サイズのリストを生成します �  aassLLiisstt(())で取得したリストに対して,, aadddd,, aaddddAAllll 等は    実行できません

33.. 解説

Page 23: Java puzzlers 2013 at JavaFesta Japan

public class CutAndPaste { public static void main(String argv[]) {"

   String firstLine = "1,2,3";   String secondLine = "4,5,6";    List<String> firstList = new ArrayList<>("

Arrays.asList(firstLine.split("\\,")));   List<String> secondList = "

Arrays.asList(secondLine.split("\\,"));    firstList.addAll(secondList);    for(String data : firstList){   System.out.print(data);    }   } }" 固定サイズのリストから、新たな可変リストを生成

33.. 解決方法

Page 24: Java puzzlers 2013 at JavaFesta Japan

�  可変のリストを作成したい場合は、固定サイズのリストより新たな可変リストのコピーを生成します

33.. 教訓

Page 25: Java puzzlers 2013 at JavaFesta Japan

4 問目

Page 26: Java puzzlers 2013 at JavaFesta Japan

public class WaltzRhythm {" public static void main(String... args) {" int count = 0;" for (int i = 0; i < Integer.MAX_VALUE; i += 3) {" count++;" }" System.out.println(count);" }"}"

44.. WWaallttzzRRhhyytthhmm �

11)) 771155882277888822 ((== IInntteeggeerr..MMAAXX__VVAALLUUEE//33)) 22)) 771155882277888833 ((== IInntteeggeerr..MMAAXX__VVAALLUUEE//33 ++ 11)) 33)) 無限ループ 44)) それ以外

Page 27: Java puzzlers 2013 at JavaFesta Japan

正解は

Page 28: Java puzzlers 2013 at JavaFesta Japan

public class WaltzRhythm {" public static void main(String... args) {" int count = 0;" for (int i = 0; i < Integer.MAX_VALUE; i += 3) {" count++;" }" System.out.println(count);" }"}"

44.. WWaallttzzRRhhyytthhmm �

44)) それ以外 ((--771155882277888833))

Page 29: Java puzzlers 2013 at JavaFesta Japan

44.. 解説 �  IInntteeggeerr..MMAAXX__VVAALLUUEE == 22114477448833664477 �  ffoorr ((iinntt ii == 00;; ii << IInntteeggeerr..MMAAXX__VVAALLUUEE ;; ii ++== 33)) {{ �  ++33 インクリメントし ccoouunntt として771155882277888822を期待します

�  CCoouunntteerr がオーバフロー �  ffoorr 文の終了条件までIInntteeggeerr..MMIINN__VVAALLUUEE -->> IInntteeggeerr..MMAAXX__VVAALLUUEE を繰り返します

0 3 6 9 12 15 18 ・・・・・・・・・ 2147483646

1 2 3 4 5 6 7 715827883

i

counter

Page 30: Java puzzlers 2013 at JavaFesta Japan

44.. 解説 ffoorr ((iinntt ii == 00;; ii << IInntteeggeerr..MMAAXX__VVAALLUUEE ;; ii ++== 33))

0 3 6 9 12 15 18 ・・・・・・・・・ 2147483646

1 2 3 4 5 6 7 715827883 counter

・・・・・・・・・ 2147483645

-2147483648

-2147483647

715827884

-2147483647

715827885

2147483642

2147483647

・・・・・・・・・ 2147483644

-715827883

-2147483648

-2147483647

-2147483645

-2147483646

2147483641

-715827884

i

counter

i

counter

i

MAX_VALUE -1

MAX_VALUE -2 MIN_VALUE +2

MIN_VALUE +1

Page 31: Java puzzlers 2013 at JavaFesta Japan

44.. 解決方法 public class WaltzRhythm {" public static void main(String... args) {" int count = 0;" for (int i = 0; i < Integer.MAX_VALUE -3 ; i += 3) {" count++;" }" System.out.println(count);" }"}"

Page 32: Java puzzlers 2013 at JavaFesta Japan

�  bbyyttee,, cchhaarr,, iinntt ,, lloonngg ((プリミティブ型)) を扱う場合、  桁のオーバフローを考慮した実装が必要です

�  オーバフローを引き起こさないために BBiiggIInntteeggeerr を使う方法もあります

44.. 教訓

Page 33: Java puzzlers 2013 at JavaFesta Japan

5 問目

Page 34: Java puzzlers 2013 at JavaFesta Japan

public class UpperLowerMatch {" public static void main(String argv[]){" Integer a1 = 10; Integer a2 = 129;" int b1 = 10; int b2 = 129;" Integer c1 = 10; Integer c2 = 129;"" System.out.print((a1==b1));" System.out.print("\t”+(a1==c1));"" System.out.print("\t”+(a2==b2));" System.out.println("\t”+(a2==c2));"}"

55.. UUppppeerrLLoowweerrMMaattcchh

11)) ttrruuee ttrruuee ttrruuee ttrruuee 22)) ffaallssee ttrruuee ffaallssee ttrruuee 33)) ttrruuee ffaallssee ttrruuee ffaallssee 44)) ttrruuee ttrruuee ttrruuee ffaallssee

Page 35: Java puzzlers 2013 at JavaFesta Japan

正解は

Page 36: Java puzzlers 2013 at JavaFesta Japan

public class UpperLowerMatch {" public static void main(String argv[]){" Integer a1 = 10; Integer a2 = 129;" int b1 = 10; int b2 = 129;" Integer c1 = 10; Integer c2 = 129;"" System.out.print((a1==b1));" System.out.print("\t”+(a1==c1));"" System.out.print("\t”+(a2==b2));" System.out.println("\t”+(a2==c2));"}"

55.. UUppppeerrLLoowweerrMMaattcchh

44)) ttrruuee ttrruuee ttrruuee ffaallssee

Page 37: Java puzzlers 2013 at JavaFesta Japan

�  AAuuttooBBooxxiinngg �  プリミティブとオブジェクトの比較は、プリミティブで計算し比較 �  オブジェクトとオブジェクトの比較は、オブジェクトの参照で比較

�  JJaavvaa..llaanngg..IInntteeggeerr は--112288 から 112277 の値の範囲でオブジェクト IIDDの値をキャッシュしており、その比較を実施します

�  つまり値が --112288 から 112277 の範囲か否かで結果が異なります Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS. "キャッシュ範囲は -XX:AutoBoxCacheMax で変更可能"

55.. 解説

Page 38: Java puzzlers 2013 at JavaFesta Japan

public class UpperLowerMatch {" public static void main(String argv[]){" Integer a1 = 10; Integer a2 = 129;" int b1 = 10; int b2 = 129;" Integer c1 = 10; Integer c2 = 129;"" System.out.print((a1==b1));" System.out.print("\t” + (a1.intValue()==c1.intValue()));"" System.out.print("\t” + (a2==b2));" System.out.println((a2.intValue()==c2.intValue()));"}"

55.. 解決方法

Page 39: Java puzzlers 2013 at JavaFesta Japan

�  オートボクシングを使え便利になっていますが、      比較においては、pprriimmiittiivvee と OObbjjeecctt の比較は     十分に注意してください

�  IInntteeggeerr の比較を行う際には iinnttVVaalluuee(()) での比較をお薦めします

55.. 教訓

Page 40: Java puzzlers 2013 at JavaFesta Japan

6 問目

Page 41: Java puzzlers 2013 at JavaFesta Japan

public class WrapWrapWrap<T> {" String wrap(Collection<?> objs) {" String result = "";" for (Object o: objs) result += o;" return result;" } " int wrap(List<Integer> numbers) {" int result = 0;" for (int num: numbers) result += num;" return result;" } " public static void main(String... args) {" List<String> strings = Arrays.asList("1", "2", "3");" System.out.println(new WrapWrapWrap().wrap(strings));" }"}"

66.. WWrraappWWrraappWWrraapp� 11))  66 22))  112233 33))  CCoommppiillee EErrrroorr 44))  tthhrrooww EExxcceeppttiioonn

Page 42: Java puzzlers 2013 at JavaFesta Japan

正解は

Page 43: Java puzzlers 2013 at JavaFesta Japan

public class WrapWrapWrap<T> {" String wrap(Collection<?> objs) {" String result = "";" for (Object o: objs) result += o;" return result;" } " int wrap(List<Integer> numbers) {" int result = 0;" for (int num: numbers) result += num;" return result;" } " public static void main(String... args) {" List<String> strings = Arrays.asList("1", "2", "3");" System.out.println(new WrapWrapWrap().wrap(strings));" }"}"

66.. WWrraappWWrraappWWrraapp�44)) tthhrrooww EExxcceeppttiioonn

Page 44: Java puzzlers 2013 at JavaFesta Japan

�  ジェネリクスを指定しない場合、RRaaww 型といいます �  RRaaww 型の場合、ジェネリクスの型情報が消失します つまり以下のクラスと同様になります

�  そのため、SSttrriinngg のリストでも、iinntt wwrraapp((LLiisstt nnuummbbeerrss))が   実行され、実行時にCCllaassssCCaassttEExxcceeppttiioonnが発生します

public class WrapWrapWrap {" String wrap(Collection objs) {...} " int wrap(List numbers) {...} " ..."}"

66.. 解説

Page 45: Java puzzlers 2013 at JavaFesta Japan

public class WrapWrapWrap<T> {" String wrap(Collection<?> objs) {" String result = "";" for (Object o: objs) result += o;" return result;" }" int wrap(List<Integer> numbers) {" int result = 0;" for (int num: numbers) result += num;" return result;" }" public static void main(String... args) {" List<String> strings = Arrays.asList("1", "2", "3");" System.out.println(new WrapWrapWrap<String>().wrap(strings));" }"}"

66.. 解決方法 �

Page 46: Java puzzlers 2013 at JavaFesta Japan

�  ジェネリクスのパラメータは正しく指定しましょう

�  JJaavvaa SSEE 77 からはダイヤモンド演算子が利用可能です

66.. 教訓

Page 47: Java puzzlers 2013 at JavaFesta Japan

7 問目

Page 48: Java puzzlers 2013 at JavaFesta Japan

public class LostAndFound {" static int getArticles(List<String> list) { return 100; }" static long getArticles(List<Integer> list) { return 200; }" public static void main(String argv[]){" List<String> listStr = new ArrayList<String>();" List<Integer> listInt = new ArrayList<Integer>();" System.out.println(getArticles(listStr));" System.out.println(getArticles(listInt));" }"}" 1)  100  ,  200

2)  200  ,  1003)  コンパイルエラー4)  ランタイムエラー

JJaavvaa SSEE 6で実行 77.. LLoossttAAnnddFFoouunndd

Page 49: Java puzzlers 2013 at JavaFesta Japan

正解は

Page 50: Java puzzlers 2013 at JavaFesta Japan

public class LostAndFound {" static int getArticles(List<String> list){ return 100;}" static long getArticles(List<Integer> list) { return 200; }" public static void main(String argv[]){" List<String> listStr = new ArrayList<String>();" List<Integer> listInt = new ArrayList<Integer>();" System.out.println(getArticles(listStr));" System.out.println(getArticles(listInt));" }"}"

4)  ランタイムエラー

JJaavvaa SSEE 6で実行 77.. LLoossttAAnnddFFoouunndd

Page 51: Java puzzlers 2013 at JavaFesta Japan

�  TTyyppee EErraassuurree :: �  ジェネリクスはコンパイル時に解決され、コンパイル後型情報は消えます。そのためこれをイレイジャ方式と呼びます

�  JJDDKK 55,, 66 では、同じイレイジャ・シグネチャを持つ、異なる返り値を持つメソッドの定義が可能でしたが、これは間違いで、JJDDKK 77 で修正されました。((RRFFEE :: 66118822995500))

77.. 解説

Page 52: Java puzzlers 2013 at JavaFesta Japan

public class LostAndFound {" static int getArticles(List<String> list) { return 100; }" static long getArticles(List<Integer> list) { return 200; }" public static void main(String argv[]){" List<String> listStr = new ArrayList<>();" List<Integer> listInt = new ArrayList<>();" System.out.println(getArticles(listStr));" System.out.println(getArticles(listInt));" }"}"

JJaavvaa SSEE 77で実行 77.. 解決策

Page 53: Java puzzlers 2013 at JavaFesta Japan

�  JJaavvaa SSEE 77 へ移行してください ((コンパイルエラー))

�  JJaavvaa のバージョン・アップ時には JJaavvaa の互換性・非互換性情報も必ずご確認ください

77.. 教訓

http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#incompatibilities

LostAndFound.java:8: エラー: 名前が競合しています。getArticles(List<Integer>)とgetArticles(List<String>)は削除後の名前が同じです static long getArticles(List<Integer> list) { return 200; }" ^"エラー1個

Page 54: Java puzzlers 2013 at JavaFesta Japan

JJaavvaa PPuuzzzzlleerrss AAttttaacckk ooff tthhee OObbjjeecctt##CClloonnee

櫻庭 祐一 寺田 佳央