web-dev-qa-db-ja.com

インターフェースを実装する抽象クラスが、インターフェースのメソッドの1つの宣言/実装を見逃すことがあるのはなぜですか?

抽象クラスを使用してインターフェイスを実装すると、Javaで奇妙なことが起こります。インターフェイスのメソッドの一部が完全に欠落している場合があります(つまり、抽象宣言も実際の実装も存在しません)文句を言わない。

たとえば、次のインターフェイスがある場合:

public interface IAnything {
  void m1();
  void m2();
  void m3();
}

次の抽象クラスは、警告またはエラーなしで楽にコンパイルされます。

public abstract class AbstractThing implements IAnything {
  public void m1() {}
  public void m3() {}
}

理由を説明できますか?

120

クラスが抽象クラスである場合、定義によりインスタンス化するサブクラスを作成する必要があるためです。サブクラスは、抽象クラスが除外したインターフェイスメソッドを実装するために(コンパイラによって)必要になります。

サンプルコードに従って、m2メソッドを実装せずにAbstractThingのサブクラスを作成してみて、コンパイラがどのようなエラーを与えるかを確認してください。このメソッドを強制的に実装します。

150
Bill the Lizard

まったく問題ありません。
抽象クラ​​スをインスタンス化することはできません。しかし、抽象クラスはm1()およびm3()の一般的な実装を格納するために使用できます。
したがって、ifm2()の実装は実装ごとに異なりますが、m1とm3は異なります。異なるm2実装だけで異なる具体的なIAnything実装を作成し、AbstractThingから派生させることができます。DRY原則を尊重します。インターフェイスが抽象クラスに対して完全に実装されているかどうかを検証するのは無益です。

更新:興味深いことに、C#がこれをコンパイルエラーとして強制することがわかりました。このシナリオでは、メソッドのシグネチャをコピーし、抽象基本クラスの 'abstract public'をプレフィックスとして追加する必要があります。(毎日新しいもの:)

33
Gishu

それはいいです。上記を理解するには、まず抽象クラスの性質を理解する必要があります。それらは、その点でインターフェースに似ています。これは、Oracleがこれについて言っていることです here

抽象クラスはインターフェイスに似ています。それらをインスタンス化することはできません。また、実装の有無にかかわらず宣言されたメソッドが混在する場合があります。

そのため、インターフェイスが別のインターフェイスを拡張するとどうなるかを考える必要があります。例えば ​​...

//Filename: Sports.Java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}

//Filename: Football.Java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

...ご覧のとおり、これも完全にコンパイルできます。単に、抽象クラスのように、インターフェイスをインスタンス化できないためです。そのため、「親」からメソッドを明示的に言及する必要はありません。ただし、すべての親メソッドシグネチャは、暗黙的に拡張インターフェイスまたは実装抽象クラスの一部になります。したがって、適切なクラス(インスタンス化できるクラス)が上記を拡張すると、すべての抽象メソッドが実装されることを保証する必要があります。

それが役立つことを願っています...そしてアラフ 'アラム!

7
Grateful

インターフェースとは、メソッドを実装せず、宣言のみを行うクラスを意味します。
一方、抽象クラスは、いくつかのメソッドの実装と、宣言だけで実装なしのメソッドを実装できるクラスです。
抽象クラスへのインターフェイスを実装すると、抽象クラスがインターフェイスのすべてのメソッドを継承したことを意味します。として、すべてのメソッドを抽象クラスに実装することは重要ではありませんが、(継承によって)抽象クラスになるため、抽象クラスは実装なしでインターフェイスにメソッドの一部を残すことができます。しかし、この抽象クラスが特定の具体的なクラスに継承される場合、それらは抽象クラスのすべての未実装メソッドを実装する必要があります。

4

与えられたインターフェース:

public interface IAnything {
  int i;
  void m1();
  void m2();
  void m3();
}

これは、Javaが実際にそれを見る方法です。

public interface IAnything {
  public static final int i;
  public abstract void m1();
  public abstract void m2();
  public abstract void m3();
}

したがって、別のabstractクラスを拡張するabstractクラスの場合と同様に、これらのabstractメソッドの一部(またはすべて)を未実装のままにすることができます。

implementinterfaceを使用する場合、すべてのinterfaceメソッドを派生classに実装する必要があるというルールは、具体的なclass実装(つまり、 abstract自体ではありません)。

abstract classを実際に作成する場合は、implementすべてのinterfaceメソッドを使用する必要があるというルールはありません(そのような場合は必須です)派生したclassabstractとして宣言するには)

4
sharhp

抽象クラスがインターフェイスを実装する場合

インターフェイスのセクションでは、インターフェイスを実装するクラスは、インターフェイスのすべてのメソッドを実装する必要があることに注意しました。ただし、クラスが抽象であると宣言されている場合、インターフェイスのすべてのメソッドを実装しないクラスを定義することは可能です。例えば、

abstract class X implements Y {   
    // implements all but one method of Y
}
class XX extends X {   
    // implements the remaining method in Y 
} 

この場合、クラスXはYを完全には実装していないため抽象クラスである必要がありますが、実際にはクラスXXはYを実装しています。

リファレンス: http://docs.Oracle.com/javase/tutorial/Java/IandI/abstract.html

2
D Vy

メソッドを実装するために抽象クラスは必要ありません。そのため、インターフェースを実装していても、インターフェースの抽象メソッドは抽象のままでかまいません。具象クラス(抽象ではない)にインターフェイスを実装しようとして、抽象メソッドを実装しない場合、コンパイラは次のことを通知します:抽象メソッドを実装するか、クラスを抽象として宣言します。

1