クラスに .equals メソッドを強制的にオーバーライドする
-
06-07-2019 - |
質問
共通のインターフェイスを実装するクラスがたくさんあります。指示。
そして、このクラスの集団は Map に移動します。
マップを正しく機能させるには、Command を実装する各クラスで、 Object.equals(Object other)
方法。
大丈夫だよ。
しかし、私は等号のオーバーライドを強制したいと思います。=> コマンドを実装するもので、equals をオーバーライドしないとコンパイル エラーが発生します。
それは可能ですか?
編集 :ところで、ハッシュコードを強制的にオーバーライドする必要もあります...
解決
いいえ、できません。ただし、インターフェイスの代わりに抽象基本クラスを使用して、 equals()
abstract:
abstract class Command {
// put other methods from Command interface here
public abstract boolean equals(Object other);
public abstract int hashCode();
}
Command
のサブクラス は、独自のequalsメソッドとhashCodeメソッドを提供する必要があります。
一般的に、APIユーザーに基本クラスの拡張を強制することは悪い習慣ですが、この場合は正当化される可能性があります。また、追加で人工的な基本クラスをCommandインターフェースに導入するのではなく、 Command
をインターフェースではなく抽象ベースクラスにすると、APIのリスクはありません。ユーザーが間違っている。
他のヒント
java.lang.Objectではなく抽象XObjectからオブジェクトを拡張できますか?
public abstract class XObject
extends Object
{
@Override
public abstract boolean equals(Object o);
}
孫がいる場合、その父親がすでにequalsメソッドとhashCodeメソッドの両方をオーバーライドしているため、抽象クラスは機能しません。
annotatinsとAPTを使用してみてください( http:// docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html )で完了します。
これは、Commandがインターフェイスまたは抽象クラスであり、equals(..)が抽象として宣言されたメソッドである場合にのみ可能です。
問題は、すべてのオブジェクトのスーパークラスであるObjectがすでにこのメソッドを定義していることです。
これが問題(実行時)であることを示す場合は、例外をスローして、APIのユーザーに強制的にオーバーライドさせることができます。しかし、少なくとも私の知る限り、コンパイル時には不可能です。
API固有のメソッド、たとえば、 CommandEquals。もう1つのオプションは(前述のとおり)Equals抽象メソッドを定義する別のクラスを拡張することです。
作成できます boolean myEquals()
で interface Command
, 、次のようにアダプターを作成します。
class MyAdapter{
Command c;
boolean equals(Object x) {
return c.myEquals((Command)x);
}
}
それからあなたはただ使用します map.put(key, new MyAdapter(command))
の代わりに map.put(key, command)
実行時チェックが必要な場合は、次のようなことができます:
interface Foo{
}
class A implements Foo {
}
class B implements Foo {
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
public static void main(String[] args) {
Class<A> clazzA = A.class;
Class<B> clazzB = B.class;
Class<Object> objectClass = Object.class;
try {
Method methodFromObject = objectClass.getMethod("equals",Object.class);
Method methodFromA = clazzA.getMethod("equals",Object.class);
Method methodFromB = clazzB.getMethod("equals",Object.class);
System.out.println("Object == A" + methodFromObject.equals(methodFromA));
System.out.println("Object == B" + methodFromObject.equals(methodFromB));
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
最初の場合はtrue、2番目の場合はfalseを出力します。 コンパイル時は、注釈を作成し、注釈処理ツールを使用してすべての注釈付きクラスが等しいことをオーバーライドすることを確認することが唯一のオプションのように見えます。
interface A{
public boolean equal2(Object obj);
}
abstract class B implements A {
@Override
public boolean equals(Object obj) {
return equal2(obj);
}
}
class C extends B {
public boolean equal2(Object obj) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
equals()
は Object
から継承されるため、 every タイプには自動 equals()
の継承された実装が利用可能。
Objectクラスからのように、equalsを強制的にオーバーライドすることは不可能だと思います。
関連するメモで、等しいをオーバーライドするたびに、Objectクラスの 'hashCode'メソッドをオーバーライドする必要があることに注意してください。クラスのインスタンスをマップのキーとして使用する場合、これは特に重要になります。この記事を確認してください: http://www.artima.com/lejava/articles/equality.html 等しい方法を正しい方法でオーバーライドする方法についてのヒントを提供します
他の回答で既に説明したように、あなたがやろうとしていることを強制することはできません。
「十分」に機能することの1つは、2番目のインターフェイスを定義し、この1つのMappableCommandを呼び出すことです。
public interface MappableCommand
{
}
このインターフェイスのドキュメントでは、クラス設計者が指定した要件を考慮した場合にのみ、クラスがこの(空の)インターフェイスを実装する必要があることを示しています。
その後、マップの値タイプをMappableCommandに設定できます。マップに追加できるのはMappableCommandのみです。
これは、Javaのデフォルトのシリアル化メカニズムによってシリアル化できるクラスに対してSerializableな(空白の)インターフェイスを実装する必要がある理由の背後にあるロジックに似ています。
これが機能しない場合、実行時エラーをスローするために解決する必要があります;
偽の編集:
この要件をより明確にしたい場合は、この方法で新しいインターフェースを定義できます
public interface MappableCommand
{
public void iOverrodeTheEqualsMethod();
public void seriouslyIPromiseThatIOverrodeIt();
}
他の提案されたソリューションのいくつかのバリエーションがあります:
public abstract class CommandOverridingEquals implements Command {
public abstract boolean equals(Object other);
public abstract int hashcode();
}
Map<String, CommandOverridingEquals> map =
new HashMap<String, CommandOverridingEquals>();
または本当に確認したい場合は、チェック済みハッシュマップを使用します。例:
Map<String, CommandOverridingEquals> map = Collections.checkedMap(
new HashMap<String, Command>(),
String.class, CommandOverridingEquals.class);
しかし、あなたが何をしても、誰かがこれをやめるのを止めることはできません:
public class AntiFascistCommand extends CommandOverridingEquals {
public boolean equals(Object other) { return super.equals(other); }
public int hashcode() { return super.hashcode(); }
...
}
この種のことは、今後のトラブルの原因になると思う傾向があります。たとえば、他の基本クラスを拡張し、(偶然に) equals
と hashcode
を所定の方法でオーバーライドする既存のコマンドクラスがたくさんあるとします。問題は、これらのクラスを使用できないことです。代わりに、それらを再実装するか、多数のラッパーを作成する必要があります。
IMO、開発者を特定の実装パターンに強制しようとするのは悪い考えです。 Javadocにいくつかの強力な警告を出し、開発者に頼って正しいことを行うことをお勧めします。
問題のマップに独自の java.util.comparator
を提供することは可能ですか?