2017-01-19 11 views
6

標準Java APIでは、がtrueを返すシナリオがありますが、equalsfalseを返します。この`==`は真であるが、 `equals`は偽であるシナリオはありますか?

class A { 
    public boolean equals(Object o) { 
     return this != o; 
    } 
} 

が実際にいくつかのオブジェクトbcのための例どこで焼いいずれかがありますように、理論的に、これはかなり自明ユーザー定義クラスに書き込むことができますが、b == ctrueが、b.equals(c)戻りfalseを返すのだろうか?さらに、そのような行動をとる可能性はありますか?

+1

はい、ほとんどです。 '=='と 'equals()'は全く違った働きをします。通常は 'equals()'が必要です。 – markspace

+0

@markspaceここで、 '=='はfalseですが、 'equals'は' true'です。 –

+0

@markspace私は彼らの仕事が異なっていることは分かっています。 '=='は参照チェックで、 'equals'はクラスメソッドです。 –

答えて

5

いいえ*。

The contract for equals has 5 rules、および最初のものは、このケースを覆う:

ザメソッドがnull以外のオブジェクト参照に同値関係を実装等しい:

  • これは再帰である:任意の非ヌル参照用値x、x.equals(x)はtrueを返す必要があります。
  • 対称です。null以外の参照値xとyについて、y.equals(x)がtrueを返す場合に限り、x.equals(y)はtrueを返す必要があります。
  • 推移的である:x.equals(y)がtrueを返し、y.equals(z)がtrueを返した場合、x.equals(z)はtrueを返す。
  • null以外の参照値xおよびyに対して、x.equals(y)の複数の呼び出しは、オブジェクトの等価比較で使用される情報が変更されていない限り、一貫してtrueを返し、常にfalseを返します。
  • null以外の参照値xの場合、x.equals(null)はfalseを返す必要があります。

再帰性はバグでは、あなたがAPIでこのようなオブジェクトを発見しない場合は、Oracleにそれを報告する違反するJavaの標準ライブラリ内の任意のオブジェクト。

*サードパーティ製のライブラリではあまり意味がありません。開発者は間違いを犯したり、equals契約を知らない。一般的に、これはサードパーティ製のライブラリのバグとしても機能しますが、YMMVになります。標準のJava APIで

+0

ああ!私は反射的な性質については考えなかった。それは動作します! –

+1

この回答は正しくありません。 JDKには、その契約を尊重しないクラスがあり、バグとはみなされません。例えば、 https://docs.oracle.com/javase/7/docs/api/java/sql/Timestamp.html#equals(java.lang.Object)。 – ruakh

+0

@ruakh興味深いです。私は、JDKが契約を締結すれば、そのクラスはすべてその契約に従うべきだと思うが、明らかにそうではないと感じている!良い発見! –

0

equalsは、x == xではなく!x.equals(x)のように実装することができます。ただし、これを行うとdocumentated behavior of equalsに違反します。有効な実装であれば、このプロパティは保持されている必要があります。だから、あなたはどこかにバグがない限り、これを行うJava標準APIのサンプルを見つけることはできません。equalsではこのように動作しない暗黙的または明示的に依存するたくさんのコードが見つかります。

1

==trueを返しますが、equalsfalse戻ります任意のシナリオがされている[は?]

ない限り、私は承知しています、と私はどんなことを確信していて発見した例はバグと見なされます。特に

xyx == y、それはx.equals(y)x.equals(x)と同じ結果に評価される場合でなければならないような参照である場合。それは再帰ある

  • equalsメソッドがnull以外の オブジェクト参照上の同値関係を実装します(そのドキュメントで)Object.equals()の契約は、部分的に、このことを言ういずれかのためにnull以外の参照値x,x.equals(x)trueを返す必要があります。

それが生成する場合はこのようにObject.equals()のいずれかのオーバーライドは、すべての参照xyため、x == y && !x.equals(y)が真実であることの結果、意味的に間違っています。標準のJava APIで

1

==trueを返しますが、equalsfalseを返します。いずれかのシナリオがあります。

私は、これはあなたが考えている正確に何であるかどうかわからないんだけど、equalsの実装はスレッドセーフである必要はなく、引数がthisと同じインスタンスである場合には明示的にチェックする必要はありません。つまり、foo.equals(foo)fooが別のスレッドで同時に変更されている場合は、falseを返すことが原則として可能です。

このチェックを含むではないと明示的に文書化されているのではないかと疑います。むしろ、これは唯一のチェックであるクラスを除いて実装の詳細とみなされます。しかし、私はsb.equals(sb)を少なくともArrayIndexOutOfBoundsExceptionになるように管理しました。sbStringBuilderの場合、別のスレッドが忙しく要素を追加しています。あなたのタイミングで特に不運な場合は、falseも返すことができます。

また、このような動作を行う可能性はありますか?

私は本当にそうは思わない。 equalsの全目的はSetMapAssert.assertEqualsのようなものをサポートすることです。 equalsを一切使用しないユースケースがたくさんありますが、を使用します。ではなくは、満足している平等の形式を表しています。身元。

しかし、ひどく重大でないコードでも、誤ってこれを引き起こすバグがある可能性は確かです。たとえば、上記のコメントで、java.util.Datejava.sql.Timestampにはデザインミスがありました(現在正式に成文化されています)。date.equals(ts)trueですが、ts.equals(date)falseです。この種の問題に対処しようとする人はjava.util.Dateに、if (that.getClass() == Date.class)のチェックを含むように修正するかもしれません。この場合、親実装を明示的にオーバーライドしていないサブクラスでは、非リフレクティブequalsの実装が行われます。 (もちろん、私はJDKにこのような間違いがあるとは思わないでしょう)

実際には継承の面でequalsを書くのはやや難しいですが、幸いにもすべての複雑さを簡単な方法で解決する既知の解決法があります。 http://www.artima.com/lejava/articles/equality.html

関連する問題