32

次の状況があるとします。

public abstract class Vehicle {
  public void turnOn() { ... }
}

public interface Flier {
  public void fly();
}

Flier実装するクラスも拡張する必要があることを保証できる方法はありVehicleますか? Flier同様の方法で他のいくつかのインターフェイスを混在させたいので、抽象クラスを作成したくありません。

例えば:

// I also want to guarantee any class that implements Car must also implement Vehicle
public interface Car {
  public void honk();
}

// I want the compiler to either give me an error saying
// MySpecialMachine must extend Vehicle, or implicitly make
// it a subclass of Vehicle. Either way, I want it to be
// impossible to implement Car or Flier without also being
// a subclass of Vehicle.
public class MySpecialMachine implements Car, Flier {
  public void honk() { ... }
  public void fly() { ... }
}
4

6 に答える 6

32

Java インターフェイスはクラスを拡張できません。クラスにはインターフェイス内で指定できない実装の詳細が含まれているため、これは理にかなっています。

この問題に対処する適切な方法はVehicle、インターフェースにも変換することによって、インターフェースを実装から完全に分離することです。Caretc はインターフェースを拡張して、Vehicleプログラマーに対応するメソッドの実装を強制することができます。すべてのインスタンス間でコードを共有したい場合Vehicleは、(おそらく抽象) クラスを、そのインターフェースを実装する必要があるクラスの親として使用できます。

于 2013-01-01T09:05:20.797 に答える
9

次のように、クラスとインターフェースを再配置できます。

public interface IVehicle {
  public void turnOn();
}

public abstract class Vehicle implements IVehicle {
  public void turnOn() { ... }
}

public interface Flier extends IVehicle {
  public void fly();
}

このようにして、 のすべての実装は、車両のプロトコルFlier、つまりを実装することが保証されます。IVehicle

于 2013-01-01T09:09:52.340 に答える
4

クラスを制御できる場合は、インターフェイスとしてVehicle抽出Vehicleしてから、基本実装を提供します。

Vehicleたとえば、使用しているフレームワークやサードパーティのライブラリの一部であるなどの理由で、クラスを制御できない場合、Java では制御できません。

あなたができる最も近いことは、ジェネリックの複数のワイルドカード表記を使用することです。

<T extends Vehicle & Car>

しかし、次のようなことをしない限り、Car に直接適用することはできません。

public interface Car<T extends Vehicle & Car>() {
    T self();
}

これは奇妙なボットであり、実際に自己を返すように自己メソッドを強制しません。これは単なる強力なヒント/提案です。

Car次のように実装します。

public class CitroenC3 extends Vehicle implements Car<CitroenC3> {
    @Override
    public CitroenC3 self() {
        return this;
    }
}

Car<?>次のように使用できます。

Car<?> car = obtainCarInSomeWay();
Vehicle v = car.self();
Car c = car.self();

どちらも有効な構文である必要があります。

ここでコンパイラが強制するのはCar<WHICH>、 WHICH must both extends Vehicleand implementとして指定することですCar。また、追加することにより、オブジェクトはオブジェクト自体であるとself()プログラマーに言っているため、仕様に準拠したい場合は、ワイルドカードインスタンスをクラスに一致させる必要があります。T

Java 8 では、self メソッドのデフォルトの実装を定義することさえできます。

また、このようなことを処理するためのより良い方法があればいいのにと思います。

于 2017-03-08T16:52:46.973 に答える
2

これは奇妙な要件ですが、Generics を使用すると、次のようなことを実現できます。

<T extends MyInterface & MyAbstractClass>
于 2013-01-01T10:52:30.227 に答える
1

interfaceこの質問は、との本質を理解していないことを示していますclass。現時点では具体的な Java 構文を忘れて、最初に理解する必要があるのは、次のことだけです。インターフェイスがクラスを拡張できるようにすることは意味がありません(実装指向です)。

Flier具体的な質問に戻ると、 aが常に の一種である ことを保証したい場合はVehicle、後者を an に変更し、前者にinterfaceそれを拡張させるだけです(1つのプロトコルを他のプロトコルから拡張することは理にかなっています)。その後、 or を実装する任意のクラス (抽象または具象) を作成できVehicleますFlier

于 2013-01-01T09:12:16.297 に答える
0
  1. 新しいパッケージを定義する
  2. メソッド「implementMe(HiddenOne)」を使用して、スコープ「デフォルト」で新しいインターフェース(つまり、HiddenOne)を作成します
  3. Vehicle と Flyer を新しいパッケージに移動します。
  4. HiddenOne から車両とフライヤーを継承する
  5. メソッドimplementMeをVehicleに実装します。

今: "Flier" から実装したいときはいつでも、 Vehicle から拡張する必要があります! (なぜなら Vehicle だけが implementMe を実装できるからです)。

これはトリッキーですが、うまく機能します。

于 2013-01-02T14:07:47.073 に答える