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
場合でも、これは出力されますが、出力されません。1
MyClass
だから基本的に、これは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)
。