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


123

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

たとえば、次のインターフェイスがあるとします。

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

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

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

理由を説明できますか?


2
抽象クラスのオブジェクトを作成することはできません。したがって、抽象クラスの実装が提供されていない限り、IAnythingのオブジェクトを作成することはできません。したがって、これはコンパイラーにとってはまったく問題ありません。コンパイラーは、IAnythingを実装する非抽象クラスは、IAnythingから宣言されたすべてのメソッドを実装する必要があることを期待しています。オブジェクトを作成できるようにするには、AbstractThingを拡張して実装する必要があるため、その実装がAbstractThingによって除外されたIAnythingのメソッドを実装していない場合、コンパイラーはエラーをスローします。
VanagaS 2017年

これと同じシナリオで独自の "AbstractThing"を拡張する具象クラスがあり、インターフェイスにメソッドの1つを実装していなかったにもかかわらず、不可解にコンパイルされていました。今、それは私が期待することをしていますが、それが以前に成功した原因を理解することはできません。私:wはファイルの1つを実行していなかったと思います。
ブレーデンベスト

あなたは、同様の質問のためのanwerを見ることができますstackoverflow.com/questions/8026580/...
ドNHU Vyの

回答:


155

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

コード例に従ってAbstractThingm2メソッドを実装せずにのサブクラスを作成してみて、コンパイラーがどのようなエラーを出すかを確認してください。このメソッドを実装する必要があります。


1
サブクラスで必要なものを確認するために1つではなく2つのクラス定義を調べる必要があるという理由だけで、インターフェイスを不完全に実装する抽象クラスに関する警告をコンパイラーがスローする必要があると思います。ただし、これは言語/コンパイラの制限です。
workmad3 2008年

3
通常、多くの抽象クラスが存在する可能性があり、「偽」の警告がすぐにあなたを圧倒し、「真」の警告を見逃してしまうため、これは良い考えではありません。考えてみれば、「abstract」キーワードは、そのクラスの警告を抑制するようコンパイラーに指示するためのものです。
belugabob 2008年

4
@workmad-インターフェースメソッドのサブセットに共通の実装がある場合、別の基本クラスに分解する方が理にかなっています(DRYが1桁のコードに勝る)
Gishu

4
空のメソッド実装を抽象クラスに入れることを要求するのは危険です。そうした場合、サブクラスのインプリメンターは、コンパイラーに問題があることを通知せずに、この非動作を継承します。
トカゲに請求する

8
workmadが示唆しているのは、メソッド本体なしで抽象クラスのメソッドを定義し、それらに抽象のマークを付けることだと思います。私には悪い考えではないようです。
–Dónal

33

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

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


7

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

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

したがって、インターフェースが別のインターフェースを拡張したときに何が起こるかを考える必要があります。例えば ​​...

//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);
}

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

お役に立てれば幸いです...そしてアラフ・アラム!


それは興味深い見方です。「抽象クラス」は、実際には「具体的なインターフェース」、つまり、いくつかの抽象的なメソッドを持つクラスではなく、いくつかの具体的なメソッドを持つインターフェースだと思います。
Giulio Piancastelli

...本当に両方のビット。しかし、確かに1つあります。それらはインスタンス化できません。
2015

4

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


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();
}

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

あなたの場合は、すべてのことをルールの方法が導き出さで実装する必要がありますが、唯一のコンクリートに適用される(されていないつまり、実装自体)。implementinterfaceinterfaceclassclassabstract

実際abstract classにそれから作成することを計画している場合、implementすべてのinterfaceメソッドを使用する必要があることを示すルールはありません(そのような場合、派生をclassとして宣言することが必須であることに注意してくださいabstract


を使用javap IAnything.classして2番目のコードスニペットを生成します。
sharhp 2017

3

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

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

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


1

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.