8

私は本当にこれを知っているべきですが、なぜか私は次のことを理解していません。

私の抽象クラスには、次の抽象メソッドが含まれています。

protected abstract RuleDTO createRowToBeCloned(RuleDTO ruleDTO);

次のような別のクラスもあります。

EvaluationRuleDTO extends from RuleDTO

次に、抽象クラスのサブクラスに、「スーパータイプメソッドをオーバーライドまたは実装する必要がある」ために許可されていない次の実装があります。

protected EvaluationRuleDTO createRowToBeCloned(EvaluationRuleDTO ruleDTO) {

ただし、次のことが許可されます。

protected EvaluationRuleDTO createRowToBeCloned(RuleDTO ruleDTO) {

これはおそらく基本的な質問だと思いますが、少し戸惑っています。オーバーライドされたメソッドでRuleDTOのサブクラスを返すことができるのに、サブクラスを渡すことができないのはなぜですか?

ありがとう

4

6 に答える 6

12

あなたはリスコフの原則を破っています。スーパークラスができることはすべて、サブクラスができる必要があります。スーパークラスは、あらゆる種類の RuleDTO を受け入れるメソッドを宣言します。ただし、サブクラスでは、EvaluationRuleDTO のインスタンスのみを受け入れます。以下のことをしたらどうなるでしょうか?

RuleDTO rule = new EvaluationRuleDTO();
rule.createRowToBeCloned(new RuleDTO());

EvaluationRuleDTO は RuleDTO であるため、RuleDTO によって定義された契約を満たす必要があります。

サブクラスのメソッドは、RuleDTO の代わりに EvaluationRuleDTO のインスタンスを返す場合があります。これは、コントラクトが RuleDTO を返すことであり、EvaluationRuleDTO が RuleDTO であるためです。

于 2012-07-19T21:52:48.307 に答える
4

これは、メソッドをオーバーライドする場合、パラメータータイプとして同じタイプまたはより一般的な(より広い)タイプを使用する必要があり、より狭いタイプは使用しないためです。

考えてみてください。より狭い型を使用してメソッドをオーバーライドできるとしたら、ポリモーフィズム機能が壊れてしまいますね。したがって、これを行うと、JBニゼットが彼の答えで述べたように、リスコフの置換原則を破ることになります。

于 2012-07-19T21:48:45.833 に答える
4

Java では、オーバーライドの戻り値の型の共分散が許可されているため、オーバーライドの戻り値の型をより派生した型として指定できます。ただし、Java では、オーバーライドのパラメーターの型の共分散は許可されていません。

前者が安全である理由は、返されるオブジェクトが少なくとも派生型の少ない型の機能を持つため、その事実に依存するクライアントは返されたオブジェクトを正しく利用できるからです。

ただし、引数の場合はそうではありません。正当な場合、ユーザーは抽象メソッドを呼び出して、派生の少ない型を渡すことができます (それは抽象クラスで宣言された型であるため) が、派生したオーバーライドは、より派生した型 (そうではありません) エラーが発生します。

理論的には、Javaは型安全であるため、パラメーター型の反分散を許可することができました。オーバーライドされたメソッドがより少ない派生引数のみを期待する場合、そこないメソッドまたはフィールドを誤って利用することはできません。残念ながら、それは現在利用できません。

于 2012-07-19T21:49:29.917 に答える
0

Java 1.5には共変の戻り型があり、それが有効である理由

 

サブクラスメソッドのリターンタイプR2は、スーパークラスメソッドのリターンタイプR1とは異なる場合がありますが、R2はR1のサブタイプである必要があります。つまり、サブクラスはタイプを返すことができ、スーパークラスのリターンタイプのサブタイプである可能性があります。

于 2012-07-19T21:48:56.427 に答える
0

次のコードを参照してください。

class A {
    A foo(A a) {
        return new A();
    }
}

class B extends A {
    @Override
    // Returning a subtype in the overriding method is fine,
    // but using a subtype in the argument list is NOT fine!
    B foo(B b) {
        b.bar();
        return new B();
    }
    void bar() {
        // B specific method!
    }
}

はい、B は A ですが、もし誰かがそうしたらどうなるでしょうか:

B b = new B();
b.foo(new A());

A には bar メソッドがありません。これが、引数がオーバーライドされるメソッドの引数の型のサブタイプにならない理由です。

オーバーライド メソッドで A または B を返すことは問題ありません。次のスニペットは、問題なくコンパイルおよび実行されます。

class A {
    A foo(A a) {
        return new B(); // B IS AN A so I can return B!
    }
}

class B extends A {
    @Override
    B foo(A b) {
        return new B(); // Overridden method returns A and 
                        // B IS AN A so I can return B!
    }

    public static void main(String[] args) {
        A b = new B();
        final A foo = b.foo(new B());
        // I can even cast foo to B!
        B cast = (B) foo;
    }
}
于 2016-12-23T18:28:39.690 に答える
0

初期の Java ではそうではありませんでしたが、Java 5.0 で変更されました。

戻り値の型だけが異なるシグネチャを持つ 2 つのメソッドを同じクラスに含めることはできません。J2SE 5.0 リリースまでは、クラスがスーパークラスから継承したメソッドの戻り値の型をオーバーライドできないことも事実でした。このヒントでは、共変の戻り型を可能にする J2SE 5.0 の新機能について学びます。これが意味することは、サブクラスのメソッドは、スーパークラスの同じシグネチャを持つメソッドによって返される型のサブクラスである型を持つオブジェクトを返す可能性があるということです。この機能により、過剰な型チェックとキャストの必要がなくなります。

ソース: http://www.java-tips.org/java-se-tips/java.lang/covariant-return-types.html

これは、オーバーライドするメソッドの戻り値の型が、オーバーライドされたメソッドの戻り値の型のサブタイプになることを意味します。

于 2012-07-19T21:53:25.827 に答える