2

インターフェイスには実装がないため、次のことは Java では不可能です。

class A {
    protected void foo() { /* A impl */ }
    protected void baz() { /* impl */ }
}
interface B {
    /* here's what's impossible to have in Java. */
    protected void foo() { /* B impl incl. call to baz() */ }
}

class C extends A {
    /* stuff that's not in B... */
}

class D extends C implements B {
    void bar() { foo(); /* uses the B impl */ }
}

class E extends A {
    void bar() { foo(); /* uses the A impl */ }
}

class F extends C implements B {
    void bar() { foo(); /* uses the B impl */ }
}

私が望むのは、D が C を継承することですが、foo()それ自体をオーバーライドする必要はありません。むしろ、単に「B からの既知の変更を使用する」ことを示したいだけです。このシナリオで正しいイディオムは何ですか?

ノート:

  • はい、デザインを変更する必要があると思います。しかし、それを何に変更しますか?それを聞きに来たのです。
  • 私はJavaを知っています。回答で抽象クラスとインターフェースを再説明しないでください。
  • これは多重継承で可能だったはずです - D は C と B の両方を継承することができました (他に競合が​​ないことを前提としています)。
  • Java 6 をお願いします。絶対に必要な場合は Java 7。Java 8 は私には関係ありません。
  • A 実装は実際にはデフォルトであり、他のクラスはそれから直接継承するため (クラス E など)、B 実装を A に移動することはできません。
  • C と B はお互いになじみがなく、互いに言及することはできません。
  • B 実装は、D に精通していない他のクラス (クラス F など) が必要とするため、D に移行することはできません。
  • 誰の実装を使用するかに関してあいまいさがないため、これは多重継承のひし形の問題ではありません。A->B,C->D というひし形のパターンもありますが。
4

6 に答える 6

4

Java 1.8を使用していない限り、インターフェースに実装を含めることはできないため、質問は間違った仮定に基づいています。つまり、A.fooinCとの実装しかありませんD

Java 1.8では、インターフェースにいわゆる仮想拡張メソッドを含めることができます。そこでは、次の構文を使用して可能になるはずです。

class ExtenderOfB {
  public static void foo(B b) {
    //...
  }
}

interface B {
  public void foo() default ExtenderOfB.foo;
}

class D extends C implements B {
  public void bar() {
    B.super.foo();
  }
}

ただし、魔法は本質的に静的メソッドを呼び出すことに要約されるため、すでに自分でそれを行うことができます。

B.fooを使用するデフォルトの実装を提供するヘルパークラスを作成し、viastatic void foo(B b)から呼び出します。D.barHelperClass.foo(this)

于 2013-01-06T12:09:09.997 に答える
0

この問題は、multilevel inheritance

class A
{
    //implementation of A
}

class B extends A
{
  public void foo()
 {
  //you can give your implementation of foo() here
 }
  //includes A's methods also.

}

class C extends B
{
  //will have methods from both A and B
} 
于 2013-01-06T12:10:09.640 に答える
0

これはあなたが探しているものですか?(これはコメントに含まれているはずです。何を探しているのかわからないのですが、正確には表示されません。)

interface A {
    void foo();
    void baz();
}
class B extends A{
    void foo(){/* B's impl. (must be impl.)*/};
    void baz(){/* B's impl. (must be impl.)*/};
}

class C extends A {
    void foo(){/* C's impl. (must be impl.)*/};
    void baz(){/* C's impl. (must be impl.)*/};
}

class D extends C {
    void foo(){/* D's impl */};
    void baz(){/* D's impl, if not included C's impl will be used */};
}

class E extends B {
    void foo(){/* E's impl, if not included B's impl will be used.*/};
    void baz(){/* E's impl, if not included B's impl will be used.*/};
}

または、BとCの両方にAのメソッドを共有させたい場合は、これを行います...

class A {
    void foo(){ /*(must be impl.)*/ };
    void baz(){ /*(must be impl.)*/ };
}

class B extends A {
    void foo(){/* B's impl, if not included A's impl will be used*/};
    void baz(){/* B's impl, if not included A's impl will be used*/};
}

class C extends A {
    void foo(){/* C's impl, if not included A's impl will be used*/};
    void baz(){/* C's impl, if not included A's impl will be used*/};
}

class D extends C {
    void foo(){/* D's impl, if not included C's impl will be used */};
    void baz(){/* D's impl, if not included C's impl will be used */};
}

class E extends B {
    void foo(){/* E's impl, if not included B's impl will be used.*/};
    void baz(){/* E's impl, if not included B's impl will be used.*/};
}

Aにfoo()を実装させたいが、baz()は実装させたくない場合は、次のように抽象化します...

abstract class A {
    void foo(){ /*(must be impl.)*/ };
    abstract void baz();
}
class B extends A{
    void foo(){/* B's impl, if not included A's impl will be used*/};
    void baz(){ /*(must be impl.)*/ };
}

class C extends A {
    void foo(){/* C's impl, if not included A's impl will be used*/};
    void baz(){ /*(must be impl.)*/ };
}

class D extends C {
    void foo(){/* D's impl, if not included C's impl will be used */};
    void baz(){/* D's impl, if not included C's impl will be used */};
}

class E extends B {
    void foo(){/* E's impl, if not included B's impl will be used.*/};
    void baz(){/* E's impl, if not included B's impl will be used.*/};
}
于 2013-01-06T12:12:57.990 に答える
0

おそらくここで再設計が必要ですが...

class D extends C implements B {
    void bar() {
        foo(); /* used the B impl */
}

がメソッド シグネチャ ( )としてinterface B 宣言され、実装されている場合にのみ有効です(有効なインターフェイスを実装するため)。したがって、を実装するメソッドが呼び出されます。これは、 に対して最もローカルであるためです。fooprotected void foo();DfooBbar()foo()DD

于 2013-01-06T12:15:56.843 に答える
0

ここでインターフェースと抽象クラスについてのちょっとした短期集中コース...

実際、Java には 1 つのクラスしか拡張できないという意味での多重継承はありませんが、複数のインターフェースを実装することはできます。

そして、抽象クラスがあります。あなたが持っているとしましょう:

interface B {
    void foo();
}

// A is abstract, and it does not implement foo(): this will be left to 
// its inheritors
abstract class A implements B {
    // Method with implementation
    protected void bar() {}
    // Method which must be implemented in inheriting classes
    abstract void baz();
}

// Concrete implementation of A: note that there is no need to specify
// "implements B" since A already does
class C extends A {
    // C must implement baz()  since it is declared abstract in A,
    // but must also implement foo() since A implements B, and A
    // has no implementation of it
}

また、抽象クラスは別の抽象クラスを拡張できます。

// D also implements B since A does.
abstract class D extends A {
    // But this time, D implements foo() from B
    @Override
    void foo() {}
}

class E extends D {
    // E must still implement the abstract baz() method declared in A
}

詳細については、適宜編集いたしますので、お気軽にお問い合わせください。

于 2013-01-06T12:14:31.683 に答える
0

このシナリオでは、1 つのクラス A がインターフェイス B を実装し、両方ともメソッドを実装する必要がありますfoo()

次に、クラス C は A を拡張し、スーパークラスによるデフォルトの実装があるため、B を実装する必要はありません。

次に、クラス D は C を拡張foo()し、メソッドbar()をオーバーライドせずにメソッドでラップします。これはイディオムです。

コード

  interface B {
    void foo();
  }

  class A  implements B {
    public void foo() {
      /* B impl */
    }
  }

  class C extends A  {
    /* stuff that's not in B... */
  }

  class D extends C  {
    void bar() {
      foo(); /* used the B impl */
    }
  }
于 2013-01-06T12:20:50.443 に答える