59

そのため、実装する必要がある一連のメソッドとのインターフェイスがあり、メソッド名は関係ありません。

このインターフェースを実装するオブジェクトは、多くの場合、コレクションに入れられ、使用したい特別な toString() 形式も持っています。

したがって、hashCode()、equals()、および toString() をインターフェースに配置して、これらのデフォルト メソッドをオーバーライドすることを忘れないようにすると便利だと思いました。しかし、これらのメソッドをインターフェイスに追加すると、これらの 3 つのメソッドが実装されていなくても、明示的にインターフェイスに配置しても、IDE/コンパイラは文句を言いません。

これが強制されないのはなぜですか? 他のメソッドを実装しないと不平を言いますが、これらの 3 つを強制することはありません。何を与える?手がかりはありますか?

4

12 に答える 12

45

クラスにこれらのメソッドのデフォルトの実装を強制的にオーバーライドさせたいようです。その場合、これを行う方法は、abstract として宣言されたメソッドを持つ抽象スーパークラスを宣言することです。例えば:

public abstract class MyBaseClass implements ... /* existing interface(s) */ {

    public abstract boolean equals(Object other);

    public abstract int hashCode();

    public abstract String toString();
}

次に、現在のクラスをextendこのクラスに変更します。

このアプローチは機能しますが、理想的なソリューションではありません。

  • 既存のクラス階層では問題になる可能性があります。

  • 既存のインターフェースを実装するクラスに、特定の抽象クラスを拡張するよう強制するのは悪い考えです。たとえば、メソッド シグネチャのパラメータを変更して、既存のインターフェイスではなく抽象クラスを使用できます。しかし、最終的にはコードの柔軟性が低下します。(とにかく、人々はこれを覆す方法を見つけることができます。たとえば、super.<method>(...)呼び出しでメソッドを「実装」する独自の抽象サブクラスを追加することによって!)

  • 特定のクラス階層/実装パターンを課すことは近視眼的です。将来の要件の変更によって、制限が問題を引き起こすことになるかどうかは予測できません。(これが、特定のクラスではなくインターフェイスに対するプログラミングを推奨する理由です。)


インターフェイスがクラスにこれらのメソッドの再宣言を強制しない理由についての実際の質問に戻ります。

これが強制されないのはなぜですか? 他のメソッドを実装しないと不平を言いますが、これらの 3 つを強制することはありません。何を与える?手がかりはありますか?

インターフェイスは、それを実装する具象クラスが各メソッドの実装を持つという制約を課します。ただし、クラス自体がこれらのメソッドを提供する必要はありません。メソッドの実装は、スーパークラスから継承できます。そして、この場合、それが起こっているのです。から継承されたメソッドjava.lang.Objectは、制約を安全にします。

JLS 8.1.5には次のように記載されています。

「宣言されているクラスが抽象クラスでない限り、各直接スーパーインターフェースのすべての抽象メンバーメソッドは、このクラスの宣言によって、または直接スーパークラスまたは直接スーパーインターフェースから継承された既存のメソッド宣言によって実装する必要があります (§8.4.8.1) 。抽象ではないクラスは抽象メソッドを持つことが許可されていないためです (§8.1.1.1)」。

于 2009-11-11T21:22:12.083 に答える
42

Java のすべてのオブジェクトは、これらのメソッドのデフォルトの実装を継承しjava.lang.ObjectObjectによって提供されます。

インターフェースに他のメソッドが含まれている場合、それらのメソッドの実装を提供してインターフェースを完全に実装しないと、Java は文句を言います。しかし、equals()hashCode()and toString()(およびあなたが言及しなかったいくつかの他のもの) の場合、実装は既に存在します。

やりたいことを実現できる方法の 1 つは、インターフェイスに別のメソッドを用意するtoPrettyString()ことなどです。次に、デフォルトのメソッドの代わりにそのメソッドを呼び出すことができますtoString()

于 2009-11-11T21:16:08.503 に答える
16

これら 3 つのメソッドはjava.lang.Objectすべて、他のすべてのクラスによって (暗黙的に) 拡張されるによって定義されます。したがって、これらのメソッドのデフォルトの実装が存在し、コンパイラは文句を言う必要はありません。

于 2009-11-11T21:16:07.963 に答える
7

インターフェイスを実装するすべてのクラスは、Object も拡張します。Object は、hashCode、equals、および toString を定義し、3 つすべてのデフォルト実装を持っています。

あなたが達成しようとしていることは良いことですが、実用的ではありません。

于 2009-11-11T21:17:05.917 に答える
6

equals() および hashCode() のオーバーライドを強制する場合は、これらのメソッドを抽象として定義する抽象スーパークラスから拡張します。

于 2009-11-11T21:22:16.733 に答える
5

からずっと来ているこれらのメソッドの実装がありますObject

于 2009-11-11T21:16:08.940 に答える
4

オーバーライドされない限り、すべてのオブジェクトは Object からこれらのメソッドを継承するため、オブジェクトにはこれら 3 つのメソッドの実装が既に含まれています。

于 2009-11-11T21:17:28.407 に答える
4

他の人があなたの実際の質問に十分に答えています。特定の問題の解決策として、独自のメソッド (getStringRepresentation、getCustomHashcode、equalsObject など) を作成し、equals、toString、および hashCode メソッドがこれらのメソッドを呼び出す基本クラスをオブジェクトに拡張させることを検討してください。

ただし、これはそもそもインターフェイスを使用する目的に反する可能性があります。これは、最初から equals、toString、および hashCode を Object クラスに含めるべきではないと一部の人々が示唆した理由の 1 つです。

于 2009-11-11T21:21:47.890 に答える
3

Java は、メソッドがどこかに定義されていることだけを気にします。インターフェースは、既に定義されている場合、初めてインターフェースから継承する新しいクラスのメソッドを再定義することを強制しません。はこれらのメソッドを既に実装しているためjava.lang.Object、これら 3 つのメソッドを独自にオーバーライドしなくても、新しいオブジェクトはインターフェイスに準拠します。

于 2009-11-11T21:18:09.700 に答える
1

Adam は、equals、hashCode、toString を強制しようとしてもうまくいかない理由を教えてくれます。Adam と Stephan によって提供されたソリューションに触れる次の実装を使用します。

public interface Distinct {
    boolean checkEquals(Object other);
    int hash();
}

public interface Stringable {
    String asString();
}

public abstract class DistinctStringableObject {

    @Override
    public final boolean equals(Object other) {
        return checkEquals();
    }

    @Override
    public final int hashCode() {
        return hash();
    }

    @Override
    public final String toString() {
        return asString();
    }
}

これで、明確に区別して文字列として表現する必要があるクラスは、DistinctStringableObject を拡張して、checkEquals、hashCode、および toString の実装を強制できます。

具体的なクラスの例:

public abstract class MyDistinctStringableObject extends DistinctStringableObject {

    @Override
    public final boolean checkEquals(Object other) {
        ...
    }

    @Override
    public final int hash() {
        ...
    }

    @Override
    public final String asString() {
        ...
    }
}
于 2013-02-03T19:48:12.760 に答える
0

孫がいる場合、その父親がすでに equals メソッドと hashCode メソッドの両方をオーバーライドしているため、抽象クラスは機能しません。その後、問題が再び発生します。

注釈と APT ( http://docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html ) を使用して実行してみてください。

于 2013-04-12T16:46:41.837 に答える
-2

デフォルトですべてのメソッドが抽象的であり、機能を提供する必要があるインターフェイスを宣言した場合でも、サブクラスでそれを実装する場合は、実装権を提供します。すべてのクラスが1つのスーパークラスのサブクラスであることがわかるように(単純にオブジェクトはすべてのクラスのスーパークラスです)、インターフェースを実装するクラスがある場合、メソッドの実装を提供する必要があります。しかし、ここで覚えておかなければならないことがあります。

インターフェイスでこれらのメソッドを宣言しなかった場合でも、最初にインターフェイスを実装したサブクラスでこの動作が引き続き発生しました。

したがって、宣言しない場合でも存在し、別のこととして、これらのメソッドと Object クラスの他のメソッドは、クラスのすべてのオブジェクトに対して存在するため、実装の必要はありません。

于 2009-11-11T21:46:25.647 に答える