4

Java に抽象クラスがある状況を考えてみましょう。

public abstract class Foo
{
    public abstract int myOperation();
}

現在、そのサブクラスのいくつかは、このように myOperation をオーバーライドできます。

class A extends Foo
{
    public int myOperation()
    {
            // Do stuff
    }
}

しかし、あるサブクラスが代わりに次のような他のデータ型を返したい場合。

class A extends Foo
{
    public Object myOperation()
    {
        // Do stuff
    }
}

クライアントが呼び出すメソッドを必ずしも選択しないように、デザインをそのまま維持するために、メソッド名を同じにする必要があります。空の実装である別のメソッドを持つか、オブジェクトを戻り値の型として使用する以外に、これに対する回避策はありますか? それとも、これは OO 設計の非常に悪い例ですか?

C++ の Covariant 戻り値の型について聞いたことがありますが、Java にはこれに対する他のメカニズムがあるかどうか疑問に思っています。

ここでインターフェイスを自由に使用することもできます。

4

6 に答える 6

8

できません。継承を使用することも、これにインターフェースを使用することもありません。これはコンパイラ エラーになるため、プログラムをまったく実行できません。

java.lang.Object必要なオブジェクトを返したり返したりすることができます。プリミティブを返す必要がある場合は、そのオブジェクト ラッパーを返すことができます。

于 2012-07-14T16:22:10.760 に答える
7

「これは OO 設計の非常に悪い例ですか」 うん。あなたはそれをすることはできません。

于 2012-07-14T16:23:25.207 に答える
5

Java には共変の戻り値の型がありますが、戻り値の型はより具体的である必要があり、あまり具体的ではありません。親クラスのメソッドが返される場合、intそのすべてのサブタイプも同様に機能する必要があります。そうしないと、そのようなメソッドの呼び出し元は、取得するタイプを実際には知りません。

Foo foo = new A()
int i = foo.method();

method() が何かを返す場合、intこのステートメントはもはや意味がありません。

あなたができるのは、スーパークラスのメソッドが戻りObject、デバイスクラスが戻るNumber場合、両方のサブクラスが戻ることができる場合ですInteger

于 2012-07-14T16:24:04.503 に答える
3

戻り値の型を派生型、つまり共変種として使用すると、さまざまなデータ型を持つことができます。プリミティブ データ型を使用する場合、それを変更することはできません。

スーパー クラス メソッドが任意の派生データ型の場合、サブクラスの戻り値の型でのオーバーライドは、同じ派生データ型またはサブクラス派生データ型にすることができます。

于 2012-07-14T16:32:14.167 に答える
2

抽象クラスで宣言されたメソッドがコントラクトを定義しているため、これは不可能です。つまり、int を返します。この契約は、すべての実装で尊重される必要があります。あなたがした場合はどうなりますか:

Foo foo = new A();
int i = foo.myOperation();

myOperation はint. それが許可されていない理由です。

ただし、次の場合は許可されます。

public abstract class Foo {
    public abstract Object myOperation();
}

public class A extends Foo {
    @Override
    public String myOperation() {
        return "some string";
    }
}

この場合、契約は尊重されます。メソッドはオブジェクトを返す必要があり、文字列を返します。文字列オブジェクトです。

于 2012-07-14T16:26:17.430 に答える
2

の契約が破られるため、これを行うことはできませんFoo

A a = new A();
someUtilityMethod(a);

...

void someUtilityMethod(Foo foo){
   int i = foo.myOperation();    // This would break
}

この原則はLiskov 置換原則と呼ばれ、OO が構築される基盤です。

于 2012-07-14T16:29:31.127 に答える