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
参照型同士の比較で
<
および>
は定義されていません。何が起こるかというと、オートボクシングによってi1
、i2
はint型に変換された後、比較が行われます。その結果、イコールがついているためtrueとなるわけです。うまく行ってしまうパターン
さらに比較ができてしまうパターンがあります。以下のコードの実行結果はどうなるでしょうか。
Integer i1 = 20; Integer i2 = 20; System.out.println(i1 == i2);
結果は以下です。
true
==
での比較なのになぜ・・・?。Integer
クラスなどのソースコードを見ると分かるのですが、Javaにおいてプリミティブ型のラッパークラスはある範囲でインスタンスをキャッシュしています。キャッシュに存在する値のインスタンスが要求された場合は、キャッシュからインスタンスを返すようになっています。(Double
とFloat
は除く)その範囲はデフォルトで-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か月間チャットで質問し放題、もしくはビデオチャットし放題のプランを用意しています。もしよろしければ以下リンクより詳細をご覧くださいませ。