バズった(´・ω・`)
こんにちは、Javaおじさんのシキムです。
40才目前で、プログラム工学に興味を持ったので本や記事で読んだ難しい話を
咀嚼して簡単な言葉で語りたいと思います。
今回は、こちらのおじさん初のバズりツイートのコードについてです。
なんでオブジェクト型を==しているんだとか、127と128で結果が違うんだっていう話でなんかめっちゃ盛り上がっております。
このなんで?に対して、AutoboxingとIntegerCacheを使ってちょっと解説してみたいと思います。
Autoboxingっていう便利な奴
Javaを使っているとおなじみ、ArrayListやクラスHashMapなどがあります。
とっても便利なもので、 オブジェクト型 なら、キーにも値にも指定することができます。
たとえば、int型であれば以下のようにArrayListを作ることができます。
ArrayList<int> list = new ArrayList<int>();
嘘です。できません。
これはint型は、プリミティブ型と呼ばれる参照ではない値を示す型だからです。(詳しくは調べてね)
でも、int型だってキーにしたいことがあります。そんな時に使われるのがInteger型です。
これは、ラッパークラスとか言われるものでザックリ説明するとint型の値を1つだけ持ったクラスです。
これを使うことで先ほどのコードも動くようになります。
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(Integer.valueOf(1));
list.add(Integer.valueOf(2));
うん、、、int型使えるって言ってもこれはちょっと面倒くさい。。。
そんな時に、いよいよ登場!!Autoboxing機能!!
こちらも、ざっくりお話しするとラッパークラスだってわかっているからコード書く時にはint型みたいに書いておけばコンパイル時によきに計らうという機能です。
先ほどのコードも、コンパイル時にAutoBoxing機能が働くため以下のコードでも同じ挙動となります。
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
ラッパークラス超便利ですね。
ほかにも、
Integer a = 1000;
Integer b = 1000;
if(a >= b)return true;
なんて書いたとしても、コンパイル時に
Integer a = Integer.ValueOf(1000);
Integer a = Integer.ValueOf(1000);
if(a.intValue() >= b.intValue())return true;
と変換してくれるので戻り値がtrueになります。
では、これはどうでしょうか?
Integer a = 1000;
Integer b = 1000;
if(a == b)return true;
これも、trueが戻り値となりそうですが、実際はa==bはfalseとなってしまいtrueが返ってくることはありません。
Autoboxingは、プリミティブ型とそのラッパークラスが変更しないとコードとして成立しない場合に自動的に動作します。(詳しくは調べてみてね)
そのため今回は、そのままオブジェクト型==オブジェクト型の判定として行けるためAutoboxingは機能しなかったようです。
だから、ツイートで、どちらも128が格納されているがIntegerとしては別のオブジェクトなのでfalseとなっていたわけです。
Integerの気遣いという罠
じゃあ、なんで127は大丈夫なのかっていうことに関しては以下をご覧いただきたい。
このメソッドは通常、渡されたintを新しく作ったIntegerオブジェクトに入れて返すのですが、なんと頻繁に使われる数字はあらかじめIntegerオブジェクトを作っておくよと気遣いをもった処理を行ってくれるのです。
このため、127ではどちらもキャッシュされているIntegerオブジェクトが渡されるので参照比較もtrueとなっていました。
今回のツイートはおじさんの勘違いへの備忘録だったのである
どんな時でもAutoBoxingがされると思っていました。でも、実際にはただのオブジェクト参照同士の判定になってしまう。
しかし、小さい値では動いてしまうのでテスト中は大丈夫だが本番で大きな数字になると急にfalseとなって原因究明が遅れそう。
こ~んな感じの懸念があってのツイートがまさかのバズったというわけです。
もし、間違った情報が混じってたらごめんなさい(´・ω・`)
以上です。