Javaで「a==b がTrueで a.equals(b)」というへんな状態になったのでメモ。
一般的に
・a == b だったら a.equals(b)は必ず成り立って
・a.equals(b) のときには a == b とは限らないというのがよくある話ですよね。
しかしこれが逆になるへんな事象がありました。
おちついて考えれば当たり前なのですが、とりあえずへんな事象を見てみましょう。
再現するのは以下のようなとても簡単なクラスでいけます。
public class ShortTest { public static void main(String[] args) { Short s1 = 8; Short s2 = 16; Short s3 = 24; System.out.println(s3 == (s1 + s2)); // true System.out.println(s3.equals(s1 + s2)); // false } }
shortのラッパークラスであるShortクラスに入れた2つの数字を足して比較しているわけですが、
なぜか答えは正しいのに==のときはTRUEでequalsで比較するとFalseが返ってきます。
ぱっと見て原理を説明できる方はちゃんとJavaのAutoBoxingと演算子の動作を理解している方ですね。
僕はいや、そんなことはないでしょっておもってしました
「==」がTrueになる理由
「==」がTrueになる理由はJava言語仕様5.6.2Chapter 5. Conversions and Contextsに書いてあります。
要約するとどちかがdouble型だったらdoubleにあわせて、floatだったらfloatにしてlongだったらlongにしてそうじゃなかったらintに変換して処理します。
なので、Short型からshortになって、それがintに変換されて比較されるので、TRUEになります。
Shortクラスのインスタンスの参照比較にならないの?というとこんなバイトコードになるのでそういう動作にはなりません。
25: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 28: aload_3 29: invokevirtual #5 // Method java/lang/Short.shortValue:()S 32: aload_1 33: invokevirtual #5 // Method java/lang/Short.shortValue:()S 36: aload_2 37: invokevirtual #5 // Method java/lang/Short.shortValue:()S 40: iadd 41: if_icmpne 48