【Java】Integer同士を==で比較してはいけない。だけど・・・

2022年5月8日日曜日

Java 開発

t f B! P L C

こんにちは、ムチャ@うつ病SE(@mutoj_rdm821)です。

Javaにおいて、==はプリミティブ型の場合は値を、参照型の場合はその参照先のインスタンスが等しいかを判定します。
Integerはクラスでその変数は参照型になるので、==は値の判定ではなく参照先のインスタンスが等しいかを判定してしまいます。値で判定するためにはequalsメソッドを使う必要があります。

書籍などでは、String型については記載があることが多いと思います。しかし、実際にある程度Javaの経験がある方に上記画面の問題を出したところ、3割くらいの方は間違った回答をしていました。

ここでは改めてInteger同士を==で比較するとどうなるのか、うまく行ってしまうパターンも交えて紹介したいと思います。

Integer同士を==で比較

以下のコードを実行するとどうなるでしょうか?
Integer i1 = 1024;
Integer i2 = 1024;
System.out.println(i1 == i2);
結果は以下です。
false
オートボクシングで数値(int型)からIntegerへの変換時にはvalueOfメソッドが呼び出されます。i1とi2はそれぞれ違うインスタンスが返されます。よって==での比較はfalseになります。

正しく判定するためにはInteger#equalsメソッドを使う必要があります。
Integer i1 = 1024;
Integer i2 = 1024;
System.out.println(i1.equals(i2));
結果は以下です。
true
まあ当たり前ですね。


Integer同士を<=,>=で比較

では以下はどうでしょうか。
Integer i1 = 1024;
Integer i2 = 1024;
System.out.println(i1 <= i2);
結果は以下です。
true
参照型同士の比較で<および>は定義されていません。何が起こるかというと、オートボクシングによってi1i2はint型に変換された後、比較が行われます。その結果、イコールがついているためtrueとなるわけです。


うまく行ってしまうパターン

さらに比較ができてしまうパターンがあります。以下のコードの実行結果はどうなるでしょうか。
Integer i1 = 20;
Integer i2 = 20;
System.out.println(i1 == i2);
結果は以下です。
true
==での比較なのになぜ・・・?。

Integerクラスなどのソースコードを見ると分かるのですが、Javaにおいてプリミティブ型のラッパークラスはある範囲でインスタンスをキャッシュしています。キャッシュに存在する値のインスタンスが要求された場合は、キャッシュからインスタンスを返すようになっています。(DoubleFloatは除く)

その範囲はデフォルトで-128〜127です。Integer型のみ、システムプロパティjava.lang.Integer.IntegerCache.high、もしくはJVMオプション-XX:AutoBoxCacheMaxで最大値のみ変更できるようになっています。実際にこれらオプションで最大値を1024に設定すると、最初のサンプルはtrueになります。

Javaの仕様上、newでインスタンス化する場合この仕組みは使えません。そのためか、Java9からプリミティブラッパークラスのコンストラクタは非推奨になっており、valueOfメソッドを使うことが推奨されています。


そんな局面があるか?

例えばMapに数値を格納していて、直接値を比較しようとするとそのような状況になります。
Map<String,Integer> map = new HashMap<>();
map.put("1", 1024);
map.put("2", 1024);
System.out.println(map.get("1") == map.get("2"));
結果はfalseです。



まとめ

Integer同士を==で比較してはいけないというお話でした。

そもそもそのような局面、プリミティブラッパークラス同士を同値判定するような場合はそれほど多くないとは思いますが、状況によっては間違った判定が行われてしまうので注意が必要です。

面倒でもequalsメソッドを使って判定を行いましょう。

Stringについては触れられていることが多いですが、プリミティブラッパークラスも同じですよということですね。

それではみなさまよきJavaライフを(´∀`)ノ


おしらせ

ココナラでJava初心者向けにメンターのサービスを販売しています。1か月間チャットで質問し放題、もしくはビデオチャットし放題のプランを用意しています。もしよろしければ以下リンクより詳細をご覧くださいませ。

▼ブログを気に入っていただけたらRSS登録をお願いします!
▼ブログランキング参加中!応援よろしくお願いします。

ブログ内検索

自己紹介

猫とガジェットが好きなJava屋さんです。うつ病で休職後退職し、1年半の休養後に社会復帰。・・・が、いろいろあって再び退職。さらに1年休職の後に復帰して、なんとかSE続けてます。茶トラのすずと一緒に生活していましたが、2014年9月4日に亡くなって1人に。

より詳細なプロフィールはこちら↓

↓更新情報を受け取るにはフォローをお願いします!

Instagramでフォロー

※ヘッダー及びアイコンで使用しているドロイド君は、googleが作成、提供しているコンテンツをベースに複製したものです。

▼ココナラでメンターサービスを販売しています。招待コード「C3VG3」で1000ポイントもらえます。
▼欲しい物リスト

ブログ アーカイブ

QooQ