人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

「x == y」が真なのに「x.equals(y)」が偽になるケースがあるのですがこれはJavaのバグでしょうか?1.5.0で試しています。

Integer x = 1;
System.out.println(x == 1.0); // true
System.out.println(x.equals(1.0)); // false



●質問者: westfish
●カテゴリ:コンピュータ
✍キーワード:Java Out バグ
○ 状態 :終了
└ 回答数 : 6/6件

▽最新の回答へ

1 ● iwaim
●10ポイント

Integerクラスのequalsメソッドはオブジェクトの比較を行うからです。「1.0」はIntegerではないのでfalseを返します。

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html#e...(java.lang.Object)

◎質問者からの返答

該当する部分のJavaのソースを読んだのでそれはわかっているのですが「そういう実装で本当にいいのか?」と思った次第です。


2 ● imaa
●10ポイント

違いはIDでの比較と変数の中身の比較です。

http://msugai.fc2web.com/java/equals.html

◎質問者からの返答

はい。

しかし、そのリンク先で述べられている通り

「==はオブジェクトの同一性の判定」「equalsは値が同じかどうかの判定」とすると

x == yの時、xとyは同じ物なのだからx.equals(y)が成り立つと考えてしまいがちです。

今回のケースはリテラルの1.0がauto-boxingされることがきっかけで、文字列の比較とはまったく逆の「==がtrueなのにequalsがfalse」という現象が起きています。

これを「従来の教科書のほとんどが間違っている」と主張すべきか「Javaの実装が変」と主張すべきかがよくわかりません。個人的には現状のInteger#equalsの実装がおかしいだけのように思います。


3 ● flashrod
●100ポイント ベストアンサー

==では二項数値昇格が起こるのにInteger.equalsの実装はそうなっていない、これはバグじゃないか、という話ですよね。

Integer#equals()の仕様は「実引数が null でなく,このIntegerオブジェクトと同じ int 値を表現するIntegerオブジェクトである場合に,またその場合にだけ,true を返す。」と決まっているので、仕様かどうかといわれれば、仕様です。

で、Autoboxingも導入されて1.0が暗黙にDoubleになっているのに気づきにくい状況でこの仕様はまずいんじゃないか、という事なら、なんとなく同情できますが、今まで偽だったnew Integer(1).equals(new Double(1.0))を真にする、という仕様変更はあり得ないと思います。

そもそも浮動小数点を==で比較しちゃだめ、っていうのは数値計算の基本だし、これはこういうものでいいのではないでしょうか。

◎質問者からの返答

なるほど。

つまり「==はオブジェクトの同一性の判定」「equalsは値が同じかどうかの判定」という理解をしていると不自然に感じてはしまうけども、現にそういう仕様だし、仕様が変更されることも考えにくい、ということですね?


4 ● Strada
●20ポイント

Javaでは過去の経緯(主に実行速度の観点)からプリミティブ型と呼ばれる型が言語仕様として残ってしまいました。

オブジェクト指向言語であるならば、「プリミティブ型と呼ばれる特殊な型は存在せずに、全てIntegerクラスのインスタンスとして管理されるべきである」と、Java否定派の方が好んで持ち出す話です。

実際にC#では完全なオブジェクト指向に近づける為、プリミティブ型を採用せずに全てInt32のようなクラスのインスタンスとして解釈されます。

いわゆるJava5のauto-boxingが働いているわけです。

とは言っても、C#でも実行速度の点では考慮しており、クラスでありプリミティブ型のような扱いを内部で行う為に構造体クラスという特殊なクラスが用意されています。

さて、質問の内容ですが、バグか?という問いにはNOとなります。

どうして挙動が変わるかに関してはauto-boxingやequalsと==の違いを理解しているようなので改めて説明する必要はないでしょう。

flashrod氏も触れているように、言語仕様としては正しいが運用上の問題を内包してしまったと捉えるのが妥当なのではないでしょうか?

経緯と問題を知った上で、現代版Effective Javaを作るのであれば「項番:XX auto-boxingに注意して比較演算子を使う」というようなTipsとなる感じがします。

よって「Javaのバグではなく、質問者のコードがバグである」というのが私の回答です。


5 ● snaruseyahoo
●0ポイント

http://www.nextindex.net/java/equals.html

java関数equals()とは、文字列が同じかどうかを判定する関数です。よってInteger x = 1;ですから、1と1.0は数値としては同じなので、System.out.println(x == 1.0); // trueとなりますが、文字列としては異なるので、System.out.println(x.equals(1.0)); // falseとなります。もし、これをtrueにしたいのであれば、equalの代わりに、equalIgnoreCase関数をお試しください。

よろしければ、下記アドレスもご覧ください。

http://www.geocities.jp/snaruse_intage/index.html

◎質問者からの返答

その解釈は正しくないと思いますし、

太極拳のページはこの質問には無関係かと思います。


1-5件表示/6件
4.前の5件|次5件6.
関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ