equals(Object)これは、メソッドをオーバーロードしても、コレクションなど、メソッドが明示的に使用されている場所での動作が変更されないためです。たとえば、次のコードを考えてみましょう。
public class MyClass {
public boolean equals(MyClass m) {
return true;
}
}
これを次のようなものに入れるとHashSet:
public static void main(String[] args) {
Set<MyClass> myClasses = new HashSet<>();
myClasses.add(new MyClass());
myClasses.add(new MyClass());
System.out.println(myClasses.size());
}
オーバーロードからすべてのインスタンスが等しいと予想され、セットが2番目のインスタンスを追加しない2場合でも、これは出力されますが、出力されません。1MyClass
だから基本的に、これはtrue:
MyClass myClass = new MyClass();
new MyClass().equals(myClass);
これはfalse:
Object o = new MyClass();
new MyClass().equals(o);
後者は、コレクションや他のクラスが同等性を判断するために使用するバージョンです。実際、これが返す唯一trueの場所は、パラメーターが明示的MyClassにそのサブタイプのインスタンスまたは1つである場所です。
編集:あなたの質問ごとに:
オーバーライドとオーバーロード
オーバーライドとオーバーロードの違いから始めましょう。オーバーライドすると、実際にメソッドを再定義します。元の実装を削除して、実際に独自の実装に置き換えます。だからあなたがするとき:
@Override
public boolean equals(Object o) { ... }
実際には、新しい実装を再リンクして、元の実装(または最後に定義したスーパークラス)equalsを置き換えています。Object
一方、あなたがするとき:
public boolean equals(MyClass m) { ... }
同じ名前でパラメーターが異なるメソッドを定義しているため、まったく新しいメソッドを定義しています。HashSetを呼び出すときはequals、次のタイプの変数で呼び出しますObject。
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
HashMap.put(そのコードは、の基礎となる実装として使用されるのソースコードからのものですHashSet.add。)
明確にするために、それが異なるものを使用するのequalsは、equalsメソッドがオーバーライドされたときであり、オーバーロードされたときだけです。@Overrideオーバーロードされたメソッドに追加しようとequalsすると、コンパイラエラーで失敗し、メソッドをオーバーライドしないと文句を言います。equalsオーバーロードしているため、同じクラスで両方のメソッドを宣言することもできます。
public class MyClass {
@Override
public boolean equals(Object o) {
return false;
}
public boolean equals(MyClass m) {
return true;
}
}
ジェネリック
ジェネリックに関してequalsは、ジェネリックではありません。それは明示的にObjectそのタイプとしてとられるので、その点は議論の余地があります。さて、あなたがこれをやろうとしたとしましょう:
public class MyGenericClass<T> {
public boolean equals(T t) {
return false;
}
}
これは次のメッセージではコンパイルされません:
名前の衝突:MyGenericClass型のequals(T)メソッドは、Object型のequals(Object)と同じ消去を行いますが、オーバーライドしません。
そして、あなたがそれをしようとする@Overrideと:
public class MyGenericClass<T> {
@Override
public boolean equals(T t) {
return false;
}
}
代わりにこれを取得します:
MyGenericClass型のメソッドequals(T)は、スーパータイプメソッドをオーバーライドまたは実装する必要があります
だからあなたは勝つことはできません。ここで起こっていることは、Javaが消去を使用してジェネリックを実装していることです。Javaがコンパイル時にすべての汎用型のチェックを終了すると、実際のランタイムオブジェクトはすべて。に置き換えられObjectます。どこにでもT、実際のバイトコードにはObject代わりに含まれています。これが、リフレクションがジェネリッククラスでうまく機能しない理由であり、のようなことができない理由ですlist instanceof List<String>。
これにより、ジェネリック型でオーバーロードできないようになります。このクラスがある場合:
public class Example<T> {
public void add(Object o) { ... }
public void add(T t) { ... }
}
add(T)クラスのコンパイルが実際に完了すると、メソッドは両方とも同じシグネチャを持つため、メソッドからコンパイラエラーが発生しますpublic void add(Object)。