JavaのAutoBoxingって..

JavaはJ2SE5(Tiger)でC#に似たAutoBoxingが導入された。

C#のintとInt32等の関係とは違い、Javaの場合はプリミティブ型をどこかの段階でラッパークラスに変換しなくてはならない。これはそもそも書き手にBoxingを意識させないためなんだろうけれど、結果として「意図しない型の変換」が発生しており、プログラミング中にBoxingされているかどうかを意識しなくてはならない、という混乱しがちな仕様になっている。

例えばリストインタフェースに対して整数をaddするテストをしてみよう。

@Test
public void autoBoxing_equality_test() {
    List list = new ArrayList();
    list.add(128);
    list.add(128);
       
OK    assertTrue(list.get(0).equals(list.get(1))); 
NG    assertTrue(list.get(0) == list.get(1));
}

このテスト、二つ目のassertTrueは失敗する。

AutoBoxingにより、Listに追加されたのはintプリミティブではなくラッパークラスであるIntegerクラスのインスタンスであることを認識していれば問題無いのだろうが、感覚的にはintをぶち込んだのだから成功を期待してしまうケースがあっても不思議ではない。(というか、似たケースで期待して嵌ったので、テストしてみたのだが)

まあ、ここまではJavaオブジェクトの等値検査にはequalsを使うことが基本であることを知っていれば驚かないのだが、なんとリストに追加する整数値を127にするとさっきまで通らなかったはずのテストが通ってしまうのだ。

@Test
public void autoBoxing_equality_test() {
    List list = new ArrayList();
    list.add(127);
    list.add(127);
       
OK    assertTrue(list.get(0).equals(list.get(1))); 
OK    assertTrue(list.get(0) == list.get(1));
}

なんじゃこりゃーーー。

この振る舞い、今日始めて知ったんだがちょっとショックだ。