インターフェイスと抽象クラスの違いをどのように説明すればよいですか?


469

インタビューの1つで、インターフェイス抽象クラスの違いを説明するように求められました。

これが私の返答です:

Javaインターフェースのメソッドは暗黙的に抽象的であり、実装を持つことはできません。Java抽象クラスには、デフォルトの動作を実装するインスタンスメソッドを含めることができます。

Javaインターフェースで宣言された変数は、デフォルトではfinalです。抽象クラスには、非final変数が含まれる場合があります。

Javaインターフェースのメンバーはデフォルトでパブリックです。Java抽象クラスは、private、protectedなどの通常のクラスメンバーのフレーバーを持つことができます。

Javaインターフェースは、キーワード「implements」を使用して実装する必要があります。Java抽象クラスは、キーワード「extends」を使用して拡張する必要があります。

インターフェースは別のJavaインターフェースのみを拡張でき、抽象クラスは別のJavaクラスを拡張して複数のJavaインターフェースを実装できます。

Javaクラスは複数のインターフェースを実装できますが、拡張できる抽象クラスは1つだけです。

しかしインタビュアーは満足せず、この記述は「本好きの知識」を表すものだと私に言った。

実用的な例を使用して、インターフェイスより抽象クラスをいつ選択するかを説明し、より実用的な対応を求められました。

どこで私は間違えましたか?


32
多分あなたの答えはあなたが理解できない何かを言っているように見えましたか?それはあなたが単にあなた自身の言葉のように見えるものに話すスタイルを変える必要があるだけかもしれません。
Kirill Kobelev 2013

19
あなたは(かなり正しい)技術的な違いのリストで答えました。インタビュアーは、より概念的な答えを探している可能性が最も高かった(たとえば、インターフェイスと抽象クラスのどちらを使用するかをどの基準で選択するか)。
Ted Hopp

15
抽象クラスであるconstをインスタンス化できない場合でも、抽象クラスにはコンストラクターがあることを忘れていました。子クラスで使用されます。インターフェースは、「何を」ではなく「どのように」を示します。なぜなら、インターフェースは、抽象の間、コントラクト(メソッドのリスト)を定義するからです。クラスは「方法」を示すこともできます(メソッドを実装します)。intを使用します。複数の継承をエミュレートできます(クラスは複数のintを実装できますが、1つのクラスしか拡張できません)。intを使用します。あなたはdifのベースタイプを持つことができます。ファミリ:Flyer f = new Plane(); Flyer f2 = new Bird(); 鳥と飛行機は同じ家族には対応していませんが、どちらも飛ぶことができます(チラシです)。
Francisco Goldenstein 2014

7
java8以降では、インターフェースにメソッドを含めることができます。オブジェクト指向の概念を超えて、これらのいわゆる「違い」はいつでも変わる可能性があります。
リングベアラー2016年

15
私はあなたの答えに何の問題もありません、そして私はインタビュアーが「本の知識」を冷笑するビジネスを持っているとは思いません。面接担当者は、質問に対する正しい答えを常に知っているとは限りません。面接によっては、そこで働かないように警告するだけのものもあります。
ローンの侯爵

回答:


513

最初に例を挙げましょう。

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

アプリケーションに3つのデータベースがあるとします。次に、そのデータベースのすべての実装で、上記の2つのメソッドを定義する必要があります。

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

しかしencryptPassword()、データベースに依存せず、各クラスで同じである場合はどうでしょうか。次に、上記は良いアプローチではありません。

代わりに、このアプローチを検討してください:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

これで、各子クラスで、1つのメソッド(データベースに依存するメソッド)を実装するだけで済みます。


97
これが本当に違いを説明しているのかわかりません...確かにそれは素晴らしいテクニックです。Java 8がC ++が正しかったこと、そして多重継承を行うことができ、使用できることをついに認めたので、インターフェイスが関数シグネチャだけでなくデフォルトの実装も提供できるようになったことも指摘する価値があると思います。そのため、インターフェースを使用することをお勧めします。
thecoshman 2015

1
@thecoshman答え(1つのメソッドが実装された抽象クラスと他の抽象が実装された抽象クラス)のように問題に取り組んだ場合、またはデフォルトのメソッド実装でインターフェイスを定義した場合、どのような違いがありますか?基本的に、私が言おうとしているのは、「インターフェースを使用することをお勧めします」とあなたが書いたということです。私の質問は、なぜですか?
ニュートリノ

1
したがって、インターフェイスでは、定義されたものの実装は実際にインターフェイスを実装するクラス次第であるのに対し、抽象クラス内のものは、クラスを拡張するクラスの「コア」であると言って差し支えないと思います。つまり、変化しません。
orrymr

4
@Neutrino Javaでは複数のインターフェースを実装できますが、それぞれが関数のデフォルト実装を提供しますが、それでも単一のクラスしか拡張できません。そのため、インターフェースを使用することで、他のインターフェースとともに、そのインターフェースを使用したい人により多くの柔軟性を提供できます。
thecoshman 2016年

3
@HiradNikoo最近のコメントは申し訳ありませんが、私はこのスレッドで偶然見つけました。クラス継承はIS-A関係と見なすこともできますが、インターフェースは「特定の機能がある」ことを示します。
Alexander Jank 2017

206

この世界では完璧なものはありません。彼らはより実用的なアプローチを期待していたかもしれません。

しかし、あなたの説明の後、少し異なるアプローチでこれらの行を追加することができます。

  1. インターフェースとは、ソフトウェア開発のさまざまなチーム間で共通の理解ドキュメントとして機能する規則(規則のように強制されるように、無視または回避できない実装を提供する必要がある規則)です。

  2. インターフェースは、何が行われるべきかという考えを与えますが、それがどのように行われるかではありません。したがって、実装は、指定されたルール(メソッドの署名が指定されていることを意味します)に従うことにより、開発者に完全に依存します。

  3. 抽象クラスには、抽象宣言、具象実装、またはその両方を含めることができます。

  4. 抽象宣言は従うべきルールのようなもので、具体的な実装はガイドラインのようなものです(そのまま使用することも、独自の実装をオーバーライドして与えることで無視することもできます)。

  5. さらに、同じシグネチャを持つどのメソッドが異なるコンテキストで動作を変更する可能性があるかは、異なるコンテキストで適切に実装するためのルールとして、インターフェース宣言として提供されます。

編集: Java 8では、インターフェースのデフォルトメソッドと静的メソッドを簡単に定義できます。

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
    }
}

クラスがSomeInterfaceを実装する場合、インターフェースのデフォルトメソッドの実装を提供する必要はありません。

次のメソッドを持つ別のインターフェースがある場合:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Javaは複数のクラスの拡張を許可しません。コンパイラが使用するスーパークラスメソッドを決定できない「ダイヤモンドの問題」が発生するためです。デフォルトのメソッドでは、ダイヤモンドの問題はインターフェースでも発生します。クラスが両方を実装している場合

SomeInterfaceOne and SomeInterfaceTwo

共通のデフォルトメソッドを実装していないため、コンパイラーはどちらを選択するかを決定できません。この問題を回避するには、Java 8では、異なるインターフェースの共通のデフォルトメソッドを実装する必要があります。いずれかのクラスが上記の両方のインターフェースを実装している場合、defaultMethod()メソッドの実装を提供する必要があります。そうしないと、コンパイラーがコンパイル時エラーをスローします。


11
+1、これは混乱を避けるために本当に良い答えです。しかし、私は何のリンクも見当たらず、なぜあなたがそれらの貴重な行を引用したのか分かりませんでした。可能であればポイントとして作成してください。
Suresh Atta 2014

インターフェースを使用して多重継承をエミュレートすること、および異なるファミリーのクラスの基本型を持つためのインターフェースを使用することについて、上記の私のコメントを読んでください。インタビュアーもそういう答えを聞きたいと思います。
Francisco Goldenstein 2014

あなたのコメントは、インターフェースの良い使用例も示しています。日々の仕事の中で感じたことを書きました。これらの単語は、専門的または正確ではない場合があります。しかし、日々のコーディングで抽象クラスとインターフェースを密接に連携させた結果、私はそのことを知りました。
Shailesh Saxena、2014

4.具体的な実装もルールであり、デフォルトの実装があります。
Luten

@Luten:私の知識によれば、問題なくルールを回避または無視できる場合、それはルールではなくガイドラインでなければなりません。私が間違っていたら訂正してください。
Shailesh Saxena

168

使用方法と実装方法の実際的な違いをまとめましたが、意味の違いについては何も述べていません。

インターフェイスは、実装クラスがあります動作の説明です。実装クラスは、クラスで使用できるこれらのメソッドを持つことを保証します。それは基本的に、クラスが行わなければならない契約または約束です。

抽象クラスは、繰り返し作成する必要はありません株式の挙動、異なるサブクラスの基礎となっています。サブクラスは動作を完了する必要があり、事前定義された動作をオーバーライドするオプションが必要です(finalまたはとして定義されていない限りprivate)。

java.utilようなインターフェイスListAbstractList、そのインターフェイスをすでに実装しているような抽象クラスを含むパッケージに、良い例があります。公式ドキュメントを説明しAbstractList、次のように:

このクラスは、Listインターフェースのスケルトン実装を提供し、「ランダムアクセス」データストア(配列など)によってサポートされるこのインターフェースを実装するために必要な労力を最小限に抑えます。


16
これが答えになるはずです。詳細のリストではなく、Javaだけでなく一般に、インターフェースと抽象クラスを区別する基本的な概念。
edc65 2016年

1
これは本当に良いです。もちろん他の答えも良いです。しかし、これはabstractキーワードについての重要な情報を伝えます。つまり、コンパイラがこれを見たときに、次の情報は不完全であり、実装が必要です。インターフェースは常に不完全ですが、抽象クラスはincomplete (abstract)メソッドを持つ必要があるため、抽象クラスです。
Rakib

85

インターフェイスは、シングルトン変数(パブリックスタティックファイナル)とパブリック抽象メソッドで構成されます。私たちは通常、何をすべきかはわかっているが、その方法がわからない場合に、リアルタイムでインターフェースを使用することを好みます。

この概念は、例によってよりよく理解できます。

支払いクラスを考えてみましょう。支払いは、PayPal、クレジットカードなど、さまざまな方法で行うことができます。そのため、通常はPaymentをmakePayment()メソッドを含むインターフェースとして使用し、CreditCardとPayPalは2つの実装クラスです。

public interface Payment
{
    void makePayment();//by default it is a abstract method
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        //some logic for PayPal payment
        //e.g. Paypal uses username and password for payment
    }
}
public class CreditCard implements Payment
{
    public void makePayment()
    {
        //some logic for CreditCard payment
        //e.g. CreditCard uses card number, date of expiry etc...
    }
}

上記の例では、CreditCardとPayPalが2つの実装クラス/ strategiesです。インターフェイスを使用すると、抽象クラスでは実現できないJavaの多重継承の概念も使用できます。

何をすべきかがわかっている機能と、実行方法がわかっているその他の機能がある場合は、抽象クラスを選択します

次の例を考えてみます。

public abstract class Burger
{
    public void packing()
    {
        //some logic for packing a burger
    }
    public abstract void price(); //price is different for different categories of burgers
}
public class VegBerger extends Burger
{
    public void price()
    {
        //set price for a veg burger.
    }
}
public class NonVegBerger extends Burger
{
    public void price()
    {
        //set price for a non-veg burger.
    }
}

将来、特定の抽象クラスにメソッド(コンクリート/抽象)を追加する場合、実装クラスはそのコードを変更する必要はありません。ただし、将来インターフェースにメソッドを追加する場合は、そのインターフェースを実装したすべてのクラスに実装を追加する必要があります。そうしないと、コンパイル時エラーが発生します。

他にも違いはありますが、これらは面接担当者が期待していた大きな違いです。うまくいけば、これは役に立ちました。


1
さて、この答えを作るには多くのことを感知し、そして我々は間の選択まで上陸するときには、一例でかなり明確だinterfaceabstract class
MAC

インターフェースを実装するクラスでメソッドの実装を定義しながら、「void makePayment();」で実装を行わずにメソッドを定義するため、「何をすべきかはわかりません」。
アブデル・Raouf

45

Abstactクラスとインターフェースの違い

  1. Java 8の抽象クラスとインターフェース
  2. 概念的な違い:

Java 8のインターフェースのデフォルトメソッド

  1. デフォルトの方法とは何ですか?
  2. デフォルトのメソッドを使用して解決されたForEachメソッドのコンパイルエラー
  3. デフォルトの方法と多重継承のあいまいさの問題
  4. Javaインターフェースのデフォルトメソッドに関する重要なポイント:

Javaインターフェイスの静的メソッド

  1. Javaインターフェイスの静的メソッド、コード例、静的メソッドとデフォルトメソッド
  2. Javaインターフェースの静的メソッドに関する重要なポイント:

Java機能インターフェース



Java 8の抽象クラスとインターフェース

Java 8インターフェースの変更には、インターフェースの静的メソッドとデフォルトメソッドが含まれます。Java 8より前のバージョンでは、インターフェースにメソッド宣言しか含めることができませんでした。ただし、Java 8以降では、デフォルトのメソッドと静的メソッドをインターフェースに含めることができます。

デフォルトメソッドを導入した後、インターフェースと抽象クラスは同じように見えます。ただし、Java 8ではまだ異なる概念です。

抽象クラスはコンストラクタを定義できます。それらはより構造化されており、状態を関連付けることができます。対照的に、デフォルトのメソッドは、特定の実装の状態を参照せずに、他のインターフェースメソッドを呼び出すという観点からのみ実装できます。したがって、両方が異なる目的で使用され、2つの間の選択は、実際にはシナリオのコンテキストに依存します。

概念的な違い:

抽象クラスは、インターフェイスのスケルトン(つまり、部分的)実装に有効ですが、一致するインターフェイスがないと存在できません。

それで、抽象クラスが効果的に可視性が低くなるように削減された場合、インターフェイスのスケルトン実装では、デフォルトのメソッドもこれを取り除くことができますか?断固として:いいえ!インターフェイスを実装するには、ほとんどの場合、デフォルトのメソッドにはないクラス構築ツールの一部またはすべてが必要です。そして、いくつかのインターフェースがそうでない場合、それは明らかに特別なケースであり、あなたを迷わせるべきではありません。

Java 8のインターフェースのデフォルトメソッド

Java 8は「デフォルトメソッド」を導入します」または(Defenderメソッド)の新機能がいます。これにより、開発者は、インターフェースの既存の実装を壊すことなく、インターフェースに新しいメソッドを追加できます。これは、具象クラスがそのメソッドの実装を提供できない場合にデフォルトとして使用するインターフェース定義実装を許可する柔軟性を提供します。

それがどのように機能するかを理解するために小さな例を考えてみましょう:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

次のクラスは、Java JDK 8で正常にコンパイルされます。

public class OldInterfaceImpl implements OldInterface {
    public void existingMethod() {
     // existing implementation is here…
    }
}

OldInterfaceImplのインスタンスを作成する場合:

OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod(); 

デフォルトの方法:

デフォルトのメソッドは決して最終的なものではなく、同期できず、オブジェクトのメソッドをオーバーライドできません。それらは常にパブリックであり、短くて再利用可能なメソッドを書く能力を厳しく制限します。

デフォルトのメソッドは、実装が含まれているため、実装クラスに影響を与えることなく、インターフェースに提供できます。実装で定義されたインターフェースに追加された各メソッドが影響を受ける場合、実装するクラスは影響を受けません。実装クラスは、インターフェースによって提供されるデフォルトの実装をオーバーライドできます。

デフォルトのメソッドを使用すると、これらのインターフェースの古い実装を壊すことなく、既存のインターフェースに新しい機能を追加できます。

デフォルトのメソッドを含むインターフェースを拡張すると、以下を実行できます。

  1. デフォルトのメソッドをオーバーライドせず、デフォルトのメソッドを継承します。
  2. サブクラスでオーバーライドする他のメソッドと同様に、デフォルトのメソッドをオーバーライドします。
  3. デフォルトのメソッドを抽象として再宣言し、サブクラスに強制的にオーバーライドさせます。

デフォルトのメソッドを使用して解決されたForEachメソッドのコンパイルエラー

Java 8では、JDKコレクションが拡張され、forEachメソッドがコレクション全体に追加されます(ラムダと連携して機能します)。従来の方法では、コードは以下のようになります、

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

この結果、各実装クラスはコンパイルエラーを伴うため、既存の実装が変更されないようにするために、必要な実装とともにデフォルトメソッドが追加されます。

Defaultメソッドを使用したIterableインターフェースは次のとおりです。

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

同じメカニズムを使用して、実装クラスを壊すことなく、JDKインターフェースにストリームを追加しました。


デフォルトの方法と多重継承のあいまいさの問題

Javaクラスは複数のインターフェースを実装でき、各インターフェースは同じメソッドシグネチャを持つデフォルトメソッドを定義できるため、継承されたメソッドは互いに競合する可能性があります。

以下の例を検討してください。

public interface InterfaceA {  
       default void defaultMethod(){  
           System.out.println("Interface A default method");  
    }  
}
 
public interface InterfaceB {
   default void defaultMethod(){
       System.out.println("Interface B default method");
   }
}
 
public class Impl implements InterfaceA, InterfaceB  {
}

上記のコードは、次のエラーでコンパイルに失敗します。

java:クラスImplは、タイプInterfaceAおよびInterfaceBからdefaultMethod()の無関係なデフォルトを継承します

このクラスを修正するには、デフォルトのメソッド実装を提供する必要があります。

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

さらに、独自の実装ではなく、スーパーインターフェースのいずれかによって提供されるデフォルトの実装を呼び出す場合は、次のようにします。

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

新しいメソッドの一部として、デフォルトの実装またはその両方を選択できます。

Javaインターフェースのデフォルトメソッドに関する重要なポイント:

  1. Javaインターフェースのデフォルトメソッドは、実装クラスを壊すことを恐れずにインターフェースを拡張するのに役立ちます。
  2. Javaインターフェースのデフォルトメソッドは、インターフェースと抽象クラスの違いを埋めています。
  3. Java 8インターフェースのデフォルトメソッドは、すべてのコレクションクラスメソッドをインターフェース自体で提供できるなど、ユーティリティクラスを回避するのに役立ちます。
  4. Javaインターフェースのデフォルトメソッドは、基本実装クラスを削除するのに役立ちます。デフォルトの実装を提供し、実装クラスがオーバーライドするクラスを選択できます。
  5. インターフェースにデフォルトのメソッドを導入する主な理由の1つは、ラムダ式をサポートするようにJava 8のコレクションAPIを拡張することです。
  6. 階層内のクラスに同じシグネチャを持つメソッドがある場合、デフォルトのメソッドは無関係になります。デフォルトのメソッドは、java.lang.Objectのメソッドをオーバーライドできません。推論は非常に単純です。これは、ObjectがすべてのJavaクラスの基本クラスであるためです。したがって、インターフェイスのデフォルトメソッドとして定義されたObjectクラスメソッドがあったとしても、Objectクラスメソッドが常に使用されるため、それは役に立ちません。そのため、混乱を避けるために、Objectクラスのメソッドをオーバーライドするデフォルトのメソッドを設定することはできません。
  7. Javaインターフェイスのデフォルトメソッドは、Defenderメソッドまたは仮想拡張メソッドとも呼ばれます。

リソースリンク:

  1. Java 8のデフォルトメソッドと抽象クラスのインターフェイス
  2. JDK 8時代の抽象クラスとインターフェース
  3. 仮想拡張メソッドによるインターフェースの進化

Javaインターフェイスの静的メソッド

Javaインターフェイスの静的メソッド、コード例、静的メソッドとデフォルトメソッド

Javaインターフェースの静的メソッドは、実装クラスでオーバーライドできないことを除いて、デフォルトのメソッドに似ています。この機能は、実装クラスでの実装が不十分な場合に、望ましくない結果を回避するのに役立ちます。簡単な例でこれを見てみましょう。

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

次に、実装が不十分なisNull()メソッドを持つ実装クラスを見てみましょう。

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");

        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

isNull(String str)は単純なクラスメソッドであり、インターフェースメソッドをオーバーライドしないことに注意してください。たとえば、@ OverrideアノテーションをisNull()メソッドに追加すると、コンパイラエラーが発生します。

アプリケーションを実行すると、次の出力が得られます。

インターフェイスのヌルチェック

Impl Null Check

インターフェースメソッドを静的からデフォルトにすると、次の出力が得られます。

Impl Null Check

MyData印刷::

Impl Null Check

Javaインターフェースの静的メソッドは、インターフェースメソッドのみに表示されます。MyDataImplクラスからisNull()メソッドを削除すると、MyDataImplオブジェクトにそれを使用できなくなります。ただし、他の静的メソッドと同様に、クラス名を使用してインターフェース静的メソッドを使用できます。たとえば、有効なステートメントは次のようになります。

boolean result = MyData.isNull("abc");

Javaインターフェースの静的メソッドに関する重要なポイント:

  1. Javaインターフェースの静的メソッドはインターフェースの一部であり、実装クラスオブジェクトには使用できません。
  2. Javaインターフェイスの静的メソッドは、nullチェック、コレクションのソートなどのユーティリティメソッドを提供するのに適しています。
  3. Javaインターフェースの静的メソッドは、実装クラスによるオーバーライドを許可しないことにより、セキュリティを提供するのに役立ちます。
  4. Objectクラスメソッドのインターフェイス静的メソッドを定義できません。「この静的メソッドはインスタンスメソッドをObjectから隠すことができません」というコンパイラエラーが発生します。これは、Objectがすべてのクラスの基本クラスであり、1つのクラスレベルの静的メソッドと同じシグネチャを持つ別のインスタンスメソッドを持つことができないため、Javaでは許可されていないためです。
  5. javaインターフェイスの静的メソッドを使用して、コレクションなどのユーティリティクラスを削除し、そのすべての静的メソッドを対応するインターフェイスに移動できます。これにより、簡単に検索して使用できます。

Java機能インターフェース

投稿を締めくくる前に、機能的なインターフェースについて簡単に紹介します。抽象メソッドが1つだけのインターフェースは、機能インターフェースと呼ばれます。

@FunctionalInterfaceインターフェースを機能インターフェースとしてマークするために、新しいアノテーションが導入されました。@FunctionalInterfaceアノテーションは、機能インターフェースに誤って抽象メソッドが追加されるのを防ぐための機能です。オプションですが、使用することをお勧めします。

関数型インターフェースは待望され、ラムダ式を使用してそれらをインスタンス化できるため、Java 8の多くの機能が求められています。ラムダ式とメソッド参照のターゲットタイプを提供するために、一連の機能インターフェースを備えた新しいパッケージjava.util.functionが追加されました。関数型インターフェイスとラムダ式については、今後の投稿で取り上げます。

リソースの場所:

  1. Java 8インターフェイスの変更–静的メソッド、デフォルトメソッド

8
私はこれらのタイプの更新された回答を正確に探しています。迅速な対応ありがとうございます。
Ravindra babu

41

最初のステートメント(Java 8リリース後)を除くすべてのステートメントは有効です。

Javaインターフェースのメソッドは暗黙的に抽象的であり、実装を持つことはできません

ドキュメントページから:

インターフェイスはクラスに似た参照型であり、定数、メソッドシグネチャ、デフォルトメソッド、静的メソッド、およびネストされた型のみを含めることができます。

メソッド本体は、デフォルトのメソッドと静的メソッドにのみ存在します。

デフォルトのメソッド:

インターフェースはデフォルトのメソッドを持つことができますが、抽象クラスの抽象メソッドとは異なります。

デフォルトのメソッドを使用すると、ライブラリのインターフェースに新しい機能を追加し、それらのインターフェースの古いバージョン用に作成されたコードとのバイナリ互換性を確保できます。

デフォルトのメソッドを含むインターフェースを拡張すると、次のことが可能になります。

  1. 拡張メソッドにデフォルトのメソッドを継承させるデフォルトのメソッドについては、まったく触れないでください。
  2. デフォルトのメソッドを再宣言してくださいabstract
  3. オーバーライドするデフォルトのメソッドを再定義します。

静的メソッド:

デフォルトのメソッドに加えて、静的メソッドをインターフェースで定義できます。(静的メソッドは、オブジェクトではなく、それが定義されているクラスに関連付けられているメソッドです。クラスのすべてのインスタンスは、静的メソッドを共有します。)

これにより、ライブラリ内のヘルパーメソッドを整理しやすくなります。

ドキュメントページからのコード例interface持つstaticdefaultする方法。

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

以下のガイドラインを使用して、インターフェースと抽象クラスのどちらを使用するかを選択します。

インターフェース:

  1. 契約を定義するには(できればステートレス-変数がないことを意味します)
  2. 無関係なクラスをリンクするには、機能ます。
  3. パブリック定数変数(不変状態)を宣言するには

抽象クラス:

  1. 密接に関連するいくつかのクラス間でコードを共有します。それ関係を確立します。

  2. 関連するクラス間で共通の状態を共有します(状態は具象クラスで変更できます)

関連記事:

インターフェイスと抽象クラス(一般的なOO)

実装と拡張:いつ使用するか?違いは何ですか?

これらの例を見ると、あなたはそれを理解することができます

関連のないクラスは、インターフェースを通じて機能を持つことができますが、関連するクラスは、基本クラスの拡張を通じて動作を変更します。


「無国籍契約」ってどういう意味?それはインターフェースに関する項目1です
Maksim Dmitriev

1
変更可能な状態がない。インターフェイスは定数を持つことができるため、抽象クラスとは異なり、データを変更することができます
Ravindra babu

1
上記のステートメントの修正。インターフェイスでは、抽象クラスとは異なり、データを変更できません
Ravindra babu

2
これが最良の答えです。これはJava8に対処するだけでなく、どちらを使用するかを特定の状況で説明します。
Shuklaswag 2017年

statelessインターフェースの概念は素晴らしいヒットです。インターフェースは状態を持つことができません(インターフェースは定数を持つことができますが、それらは最終的/静的なので不変です)。
カイフア

22

あなたの説明はまともですが、教科書からすべてを読んでいるように見えましたか?:-/

私がもっと気になるのは、あなたの例はどれほどしっかりしていたのですか?アブストラクトとインターフェースのほとんどすべての違いを含めることに迷惑をかけましたか?

個人的には、このリンクをお勧めします:http : //mindprod.com/jgloss/interfacevsabstract.html#TABLE

違いの完全なリストについては..

それがあなたと他のすべての読者の将来のインタビューに役立つことを願っています


1
リンクが共有されていることは本当に素晴らしいです
Premraj '26 / 06/15

デフォルトのキーワードを使用して、Javaインターフェースにデフォルトの実装を提供できます
Ogen

21

ジュニア開発者の多くは、インターフェース、抽象クラスと具象クラスを同じもののわずかなバリエーションと考えて間違いを犯し、それらの1つを純粋に技術的な理由で選択します。多重継承が必要ですか?一般的な方法を配置するための場所が必要ですか?単なる具体的なクラス以外のものに悩む必要がありますか?これは誤りであり、これらの質問に隠されているのが主な問題です:"I"。自分でコードを書くとき、自分でコードを作成するとき、コードで作業している、またはコードを使用している他の現在または将来の開発者について考えることはほとんどありません。

インターフェースと抽象クラスは、技術的な観点からは明らかに似ていますが、意味と目的が完全に異なります。

概要

  1. インターフェースは、いくつかの実装があなたのために果たす契約定義します

  2. 抽象クラスは、実装で再利用できるデフォルトの動作提供します

上記の2つの点は、インタビュー時に私が探しているものであり、十分にコンパクトな要約です。詳細については、以下をお読みください。

代替要約

  1. インターフェースは公開APIを定義するためのものです
  2. 抽象クラスは内部で使用するためのものであり、SPIを定義するためのものです。

例として

言い換えると、具象クラスは実際の作業を非常に具体的な方法で実行します。たとえば、ArrayListはメモリの連続した領域を使用して、オブジェクトのリストをコンパクトな方法で格納します。これにより、高速のランダムアクセス、反復、およびインプレース変更が提供されますが、挿入、削除、および場合によっては追加でもひどいです。その間、LinkedListは、二重リンクされたノードを使用してオブジェクトのリストを格納します。代わりに、高速の反復、インプレース変更、挿入/削除/追加を提供しますが、ランダムアクセスではひどいです。これらの2種類のリストは、さまざまなユースケースに合わせて最適化されており、どのように使用するかが非常に重要です。頻繁にやり取りしているリストからパフォーマンスを絞り出そうとしている場合、およびリストのタイプを選択する場合は、インスタンス化しているリストを慎重に選択する必要があります。

一方、リストの高レベルのユーザーは、実際にそれがどのように実装されるかを気にしません。これらの詳細から隔離する必要があります。JavaがListインターフェースを公開しておらず、List実際にLinkedList現在ある具体的なクラスしか持っていなかったとしましょう。すべてのJava開発者は、実装の詳細に合わせてコードを調整します。ランダムアクセスを回避する、キャッシュを追加してアクセスを高速化する、またはArrayList自分で再実装するだけですが、実際にListのみ機能する他のすべてのコードとは互換性がありません。それはひどいでしょう...しかし、Javaマスターが実際に、リンクリストがほとんどの実際のユースケースではひどいことに気付き、その唯一の配列リストに切り替えることにしたと想像してください。Listクラス利用可能。これは世界中のすべてのJavaプログラムのパフォーマンスに影響を与え、人々はそれについて満足しません。そして主な犯人は、実装の詳細が利用可能であったことであり、開発者はそれらの詳細が信頼できる永久的な契約であると想定していました。これが、実装の詳細を隠し、抽象的なコントラクトのみを定義することが重要である理由です。これがインターフェイスの目的です。メソッドが受け入れる入力の種類と期待される出力の種類を定義します。将来の更新で変更される可能性のある内部の詳細に合わせてコードを微調整するようにプログラマを誘惑するすべての根拠を公開する必要はありません。 。

抽象クラスは、インターフェースと具象クラスの中間にあります。これは、実装が共通または退屈なコードを共有するのに役立つはずです。たとえば、AbstractCollectionisEmpty、サイズが0に基づいて、contains反復して比較し、addAll繰り返しとしてadd、などの基本的な実装を提供します。これにより、実装はそれらを区別する重要な部分、つまり実際にデータを格納および取得する方法に焦点を合わせることができます。

別の視点:APIとSPI

インターフェースは、コードのさまざまな部分間の凝集度の低いゲートウェイです。これにより、内部で何かが変更されたときにすべてのライブラリユーザーを壊すことなく、ライブラリが存在し、進化することができます。これは、アプリケーションプログラミングクラスではなく、アプリケーションプログラミングインターフェイスと呼ばれます。小規模では、十分に文書化されたインターフェースを介してさまざまなモジュールを分離することにより、複数の開発者が大規模プロジェクトで共同作業を成功させることもできます。

抽象クラスは、あるレベルの実装の詳細を想定して、インターフェースを実装するときに使用される凝集度の高いヘルパーです。あるいは、SPI、サービスプロバイダーインターフェイスの定義に抽象クラスが使用されます。

APIとSPIの違いは微妙ですが重要です。APIの場合は、だれそれを使用するかを重視し、SPIの場合はだれそれを実装するかを重視します。

APIへのメソッドの追加は簡単で、APIの既存のユーザーはすべてコンパイルされます。すべてのサービスプロバイダー(具体的な実装)が新しいメソッドを実装する必要があるため、SPIへのメソッドの追加は困難です。インターフェイスを使用してSPIを定義する場合、プロバイダーはSPIコントラクトが変更されるたびに新しいバージョンをリリースする必要があります。代わりに抽象クラスを使用する場合、新しいメソッドは既存の抽象メソッドで定義することも、空のthrow not implemented exceptionスタブとして定義することもできます。これにより、古いバージョンのサービス実装を引き続きコンパイルして実行できます。

Java 8とデフォルトのメソッドに関する注意

Java 8ではインターフェースのデフォルトメソッドが導入されたため、インターフェースと抽象クラスの境界がさらにぼやけていますが、これは実装でコードを再利用できるようにするためではなく、APIとSPIの両方として機能するインターフェースを簡単に変更できるようにするためです(または抽象クラスの代わりにSPIを定義するために誤って使用されています)。

「本の知識」

OPの回答で提供される技術的な詳細は、「本の知識」と見なされます。これは、通常、学校や言語に関するほとんどの技術書で使用されているアプローチです。特に大規模なアプリケーションでは、実際の使用方法ではなく、事柄とは何か

ここに類推があります:質問があったと仮定:

プロムナイト、車、ホテルの部屋のレンタルには何がいいですか?

技術的な答えは次のように聞こえます:

まあ、車ではもっと早くできるが、ホテルの部屋ではもっと快適にできる。一方、ホテルの部屋は1か所だけですが、車の中では、眺めの良いポイントやドライブインシアターなど、より多くの場所でそれを行うことができます。または他の多くの場所、または複数の場所でさえ。また、ホテルの部屋にはシャワーがあります。

それはすべて真実ですが、2つのまったく異なるものであり、両方を異なる目的で同時に使用できるという点を完全に逃しています。「実行する」という側面は、2つのオプションのどちらについても最も重要なことではありません。答えには視点がありません。真の「事実」を正しく提示しながら、未熟な考え方を示しています。


「低結合」という意味ですか?
user2418306 2017年

@ user2418306いいえ、凝集度はより一般的な用語で、結合を含みますが、それらは密接な同義語であり、どちらの用語でも機能します。
セルジュDumitriu 2017年

9

次のように考えてみてください。

  • クラスと抽象クラスの関係は「is-a」型です
  • クラスとインターフェースの関係はタイプ「has-a」です

したがって、抽象クラスMammals、サブクラスHuman、およびインターフェイスDrivingがある場合、次のように言うことができます。

  • それぞれの人間は哺乳類です
  • 各人間が運転している(行動)

私の提案は、本の知識フレーズは、彼が両方の意味の違いを聞きたかったことを示しているということです(他の人がすでに提案しているように)。


9

インターフェイスは「コントラクト」であり、コントラクトを実装するクラスはメソッドの実装を約束します。クラスではなくインターフェイスを作成する必要があった例は、ゲームを2Dから3Dにアップグレードするときでした。ゲームの2Dバージョンと3Dバージョンの間でクラスを共有するためのインターフェースを作成する必要がありました。

package adventure;
import java.awt.*;
public interface Playable {
    public void playSound(String s);
    public Image loadPicture(String s);    
}

次に、環境に基づいてメソッドを実装しながら、ロードしているゲームのバージョンがわからないオブジェクトからこれらのメソッドを呼び出すことができます。

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

通常、ゲームワールドでは、ワールドはゲームのメソッドを実行する抽象クラスである場合があります。

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

6

抽象クラスは、具象(実装されたメソッド)のコレクションや実装されていないメソッドの純粋な抽象化ではありません。しかし、インターフェースは純粋な抽象化です。実装されていないメソッドのみがあり、具象メソッドはありません。

なぜ抽象クラスなのか?

  1. ユーザーがすべてのオブジェクトに共通の機能を記述したい場合。
  2. 抽象クラスは、エンドユーザーに影響を与えずに機能を追加する将来の再実装に最適です。

なぜインターフェースなのか?

  1. ユーザーがオブジェクトの異なる機能になる異なる機能を書きたい場合。
  2. インターフェースは、インターフェースの公開後に要件を変更する必要がない場合に最適です。

5

インタフェースは、公に効果のいくつかの種類を持っているために文書化された遺伝子のセットのようである:A DNAテストは、私はそれらを持っているかどうか私に教えてくれる-と私がしなければ、私は公にそれは私が「キャリアだと知られて作ることができます「そして私の行動や状態の一部はそれらに準拠します。(もちろん、私はこの範囲外の特性を提供する他の多くの遺伝子を持っているかもしれません。)

抽象クラスはの死んだ先祖のようであるシングル男女種彼女は生活に持ち込むことはできませんが、生きている(すなわち:(*)非抽象)子孫継承すべての彼女の遺伝子。

(*)この比喩を拡張するために、種のすべてのメンバーが同じ年齢まで生きているとしましょう。つまり、死んだ祖先のすべての祖先も死んでいる必要があります。同様に、生きている祖先のすべての子孫も生きている必要があります。


4

私は仕事のためにインタビューをします、そして私はあなたの答えも好ましくないように見ます(申し訳ありませんが、非常に正直です)。違いについて読んで回答を修正したように聞こえますが、実際に使用したことはないでしょう。

それぞれを使用する理由についての適切な説明は、違いを正確に説明するよりもはるかに優れています。雇用主ultimatleyは、インタビューで実証するのが難しい可能性のある、彼らが知らないことをプログラマーにしてほしいと思っています。あなたが与えた答えは、技術的またはドキュメントベースの仕事に応募するが、開発者の役割には応募しない場合に適しています。

今後のインタビューで頑張ってください。

また、この質問に対する私の答えは、あなたが提供した技術的な資料ではなく、インタビューのテクニックについての詳細です。おそらくそれについて読むことを検討してください。https://workplace.stackexchange.com/は、この種のことには最適な場所です。


1
どのように答えたのですか?それは私を助けることができるかもしれません。
code_fish 2013年

あなたに答えを与えることはあなたがそれを解決するのを助けるよりもずっと少ないことを提供します、基本的にあなたがそれぞれを使うときの実際的な例を与え、それぞれが異なるタスクに適している理由を説明します。
エイドリアン

4

多重継承におけるダイアモンド問題を回避するには、Javaのインターフェースを選択します。

すべてのメソッドをクライアントで実装したい場合は、インターフェースを使用します。これは、アプリケーション全体を抽象的に設計することを意味します。

共通点がわかっている場合は、抽象クラスを選択します。たとえば、抽象クラスを取りCarます。より高いレベルでは、のような一般的な車のメソッドを実装しますcalculateRPM()。これは一般的な方法であり、クライアントに独自の動作などを実装させることができます
calculateMaxSpeed()。おそらく、日常業務で遭遇したリアルタイムの例をいくつか挙げることで説明したでしょう。



3

私が観察した主な違いは、抽象クラスはすでに実装されているいくつかの一般的な動作を提供し、サブクラスはそれらに対応する特定の機能を実装するだけでよいことです。ここで、インターフェースについては、実行する必要があるタスクのみを指定し、インターフェースによる実装は指定されません。それ自体と実装されたクラスとの間の契約を指定していると言えるでしょう。


3

複数の面接で同じ質問に直面したこともあり、面接担当者を説得するのはあなたの時間を悲惨なものにしていると私は信じています。上記のすべての答えを内在している場合は、オブジェクト指向をより説得力のあるものにするために、もう1つ重要なポイントを追加する必要があります。

ルールの変更を計画していない場合は、サブクラスを追跡するために、インターフェースを変更することはできないため、長期的にはインターフェースを使用します。変更を行う場合は、他のすべてのサブクラスでの変更。ただし、機能を再利用し、いくつかのルールを設定して、変更のためにオープンにしたい場合は、抽象クラスを使用します。

このように考えると、消費可能なサービスを使用したり、コードを世界に提供したりして、何かを変更する機会があり、セキュリティチェックを行うとします。そして、私がコードのコンシューマーであり、更新後の1朝、私のEclipseですべての読み取りマークを見つけます。アプリケーション全体がダウンしています。したがって、このような悪夢を防ぐには、Abstract over Interfacesを使用します

面接担当者をある程度納得させるかもしれないと思います...幸せな面接を先に。


2

2つの密接に関連するクラス間で動作を共有しようとすると、共通の動作を保持し、両方のクラスの親として機能する抽象クラスを作成します。

Type、つまりオブジェクトのユーザーが確実に呼び出すことができるメソッドのリストを定義しようとすると、インターフェイスを作成します。

たとえば、抽象クラスは動作を共有するためのものなので、1つの具象サブクラスを持つ抽象クラスを作成することはありません。しかし、実装が1つだけのインターフェースを作成することもできます。私のコードのユーザーは、実装が1つしかないことを知りません。実際、将来のリリースでは、いくつかの実装が存在する可能性があります。これらの実装はすべて、インターフェイスを作成したときに存在しなかった新しい抽象クラスのサブクラスです。

それも少々本気すぎるように思われたかもしれません(私が覚えているどこにもそのように配置されているのを見たことがありませんが)。インタビュアー(またはOP)が実際に私の個人的な経験をもっと欲しがっていれば、インターフェースが必要性から発展し、その逆も同様であるという逸話に備えることができたでしょう。

もう一つ。 Java 8では、デフォルトのコードをインターフェースに挿入できるようになり、インターフェースと抽象クラスの境界がさらにぼやけています。しかし、私が見た限りでは、その機能はJavaコアライブラリのメーカーによっても過剰に使用されています。その機能が追加されました。これは、バイナリの非互換性を作成することなくインターフェイスを拡張できるようにするためです。しかし、インターフェースを定義して真新しいタイプを作成する場合、インターフェースはインターフェースである必要があります。一般的なコードも提供したい場合は、必ずヘルパークラス(抽象または具象)を作成してください。変更したい機能を最初から雑然としないでください。


2

インターフェイスと抽象クラスの基本的な違いは、インターフェイスは多重継承をサポートしていますが、抽象クラスはサポートしていません。

抽象クラスでは、インターフェースのようなすべての抽象メソッドを提供することもできます。

なぜ抽象クラスが必要なのですか?

一部のシナリオでは、ユーザーリクエストの処理中に、抽象クラスがユーザーの意図を認識しません。そのシナリオでは、クラスで1つの抽象メソッドを定義し、このクラスを拡張するユーザーに質問します。抽象メソッドで意図を提供してください。この場合、抽象クラスは非常に便利です

なぜインターフェースが必要なのですか?

たとえば、その分野で経験のない作品があるとします。たとえば、建物やダムを建設したい場合、そのシナリオで何をしますか?

  1. あなたはあなたの要件が何であるかを識別し、その要件と契約を結ぶでしょう。
  2. 次に、入札を呼び出してプロジェクトを構築します
  3. 誰がプロジェクトを構築するか、それはあなたの要件を満たすべきです。ただし、構築ロジックはベンダーごとに異なります。

ここでは、彼らがどのように構築したかについての論理については気にしません。最終的なオブジェクトは私の要件を満たすかどうか、それは私の要点だけでした。

ここでは、インターフェースとコンストラクターと呼ばれる要件をインプリメンターと呼びます。


2

一言で言えば、私はこのように答えます:

  • クラス階層による継承は状態の継承を意味します。
  • 一方、インターフェースによる継承は動作の継承を意味します

抽象クラスはこれら2つのケースの間にあるものとして扱うことができ(これはいくつかの状態を導入しますが、動作を定義する必要もあります)、完全抽象クラスはインターフェイスです(これは、C ++でのみ仮想メソッドから構成されるクラスのさらなる開発であり、私がその構文を知っている限り)。

もちろん、Java 8以降は少し変更されましたが、考え方は同じです。

コンパイラー・チームにインタビューされていないのであれば、これは典型的なJavaインタビューには十分だと思います。


1

私が理解しているところによると、実装されていない最終的な変数とメソッドで構成されるインターフェイスは、クラスによって実装され、互いに関連するメソッドまたはメソッドのグループを取得します。一方、非ファイナル変数と実装を含むメソッドを含むことができる抽象クラスは、通常、ガイドとして、またはすべての関連クラスまたは類似クラスが継承するスーパークラスとして使用されます。つまり、抽象クラスには、そのすべてのサブクラスによって共有されるすべてのメソッド/変数が含まれています。


1

抽象クラスでは、メソッドのデフォルト実装を書くことができます!しかし、インターフェイスではできません。基本的に、インターフェースには、インターフェースを実装するクラスによって実装されなければならない純粋な仮想メソッドが存在します。


1

はい、あなたの応答は技術的には正しかったが、あなたが間違っていたところはそれらを示していなかったので、あなたはどちらを選ぶかの長所と短所を理解しています。さらに、彼らはおそらく、将来のアップグレードとのコードベースの互換性に不安/びびっていました。このタイプの応答は(あなたが言ったことに加えて)助けになったかもしれません:

「インターフェイスクラスではなく抽象クラスを選択することは、コードの将来がどのようになるかを予測することによって決まります。

抽象クラスを使用すると、既存のコードを壊すことなく、今後も抽象クラスに動作を追加できるため、上位互換性が向上します->これは、インターフェイスクラスでは不可能です。

一方、インターフェイスクラスは、抽象クラスよりも柔軟性があります。これは、複数のインターフェースを実装できるためです。問題は、Javaには複数の継承がないため、抽象クラスを使用しても他のクラス階層構造を使用できないことです...

つまり、コードベースに既存/デフォルトの実装がない場合は、最終的には、優れた一般的な経験則として、インターフェイスクラスを使用することをお勧めします。また、将来クラスを更新することがわかっている場合は、抽象クラスを使用して互換性を維持してください。」

次のインタビューで頑張ってください!


1

2つの違いを示すために、実際的なシナリオを使用して回答してみます。

インターフェースにはペイロードがありません。つまり、状態を維持する必要がないため、コントラクト(機能)をクラスに関連付けるだけの方が適しています。

たとえば、いくつかのアクションを実行するタスククラスがあるとします。別のスレッドでタスクを実行するために、スレッドクラスを拡張する必要はありません。タスクにRunnableインターフェースを実装させる(つまり、run()メソッドを実装する) )次に、このTaskクラスのオブジェクトをThreadインスタンスに渡し、そのstart()メソッドを呼び出します。

ここで、Runnableが抽象クラスであったかどうかを尋ねることができますか?

技術的にはそれが可能でしたが、設計が賢明ではありませんでした。

  • Runnableには状態が関連付けられておらず、run()メソッドのデフォルト実装も提供されていません。
  • タスクはそれを拡張する必要があるため、他のクラスを拡張できませんでした
  • タスクはRunnableクラスに特化して提供するものは何もありません。必要なのはrun()メソッドをオーバーライドすることだけです。

言い換えると、タスククラスは、それをスレッドにするスレッドクラスを拡張するためにRunnableインターフェースを実装することで実現した、スレッドで実行する機能を必要としました。

機能(契約)を定義するためのインターフェースを用意し、抽象クラスを使用してその機能のスケルトン(共通/部分)実装を定義します。

免責事項:愚かな例が続きます。判断しないようにしてください:-P

interface Forgiver {
    void forgive();
}

abstract class GodLike implements Forgiver {
    abstract void forget();
    final void forgive() {
        forget();
    }
}

これで、あなたはGodLikeになる選択が与えられましたが、Forgoverのみ(つまり、GodLikeではない)を選択して、次のことを行うことができます。

class HumanLike implements Forgiver {
    void forgive() {
       // forgive but remember    
    }
}

または、あなたはGodLikeになることを選択して、

class AngelLike extends GodLike {
    void forget() {
       // forget to forgive     
    }
}

java 8インターフェースを備えたPSは、静的(デフォルトの(実装可能な)実装)メソッドも持つことができるため、b / wインターフェースと抽象クラスの違いがさらに絞り込まれます。


1

ほとんどすべてがここですでにカバーされているようです。abstractクラスの実用的な実装に関するもう1つのポイントを追加します。

abstractキーワードは、クラスがインスタンス化されないようにするためにも使用されます。インスタンス化したくない具体的なクラスがある場合は、それを作成しabstractます。


1

うーん今、人々は空腹の実用的なアプローチです、あなたは全く正しいですが、インタビュアーのほとんどは彼らの現在の要件に従って見え、実用的なアプローチを望んでいます。

回答が終わったら、例にジャンプしてください:

概要:

たとえば、すべての従業員に共通のパラメタを持つ給与関数があります。次に、部分的に定義されたメソッド本体を持つCTCと呼ばれる抽象クラスを作成できます。これは、すべてのタイプの従業員によって拡張され、追加の利点に従って再利用されます。一般的な機能のため。

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

インターフェース

Javaのインターフェイスでは、インターフェース機能を拡張せずにインターフェース機能を使用でき、アプリケーションに導入する機能のシグネチャの実装を明確にする必要があります。それはあなたに定義を強制するでしょう。さまざまな機能。

public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "contract";
    }

}

class PermanentOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "permanent";
    }

}

抽象クラスとして定義されたメソッドによっても、抽象クラスでそのような強制されたアクティビティを行うことができます。クラスは、抽象関数をオーバーライドするまで、抽象クラスremin抽象クラスを拡張します。


1

私が理解したことと私がどのようにアプローチしたかから、

インターフェースは仕様/契約に似ています。インターフェースクラスを実装するクラスは、抽象クラスで定義されたすべてのメソッドを実装する必要があります(デフォルトのメソッド(Java 8で導入)を除く)

クラスのいくつかのメソッドといくつかのメソッドに必要な実装がわかっているときにクラスの抽象を定義するのに対して、私はまだ何が実装されるかわかりません(関数のシグネチャは知っているかもしれませんが、実装はわかりません)。開発の後半で、これらのメソッドの実装方法がわかったときに、この抽象クラスを拡張してこれらのメソッドを実装できるようにするためです。

注:メソッドが静的またはデフォルトでない限り、インターフェースメソッドに関数本体を含めることはできません。


0

インタビュアーが狙っていたのは、おそらくインターフェースと実装の違いだったと思います。

Javaインターフェイスではなく、より一般的な用語での「インターフェイス」であるコードモジュールへのインターフェイスは、基本的に、インターフェイスを使用するクライアントコードとの契約です。

コードモジュールの実装は、モジュールを機能させる内部コードです。多くの場合、特定のインターフェイスを複数の異なる方法で実装でき、クライアントコードが変更を認識していなくても実装を変更できます。

Javaインターフェースは、上記の一般的な意味でのインターフェースとしてのみ使用して、実装を指定せずに、クラスを使用するクライアントコードの利益のためにクラスの動作を定義する必要があります。したがって、インターフェイスには、クライアントコードによって呼び出されることが予想されるメソッドのメソッドシグネチャ(名前、戻り値の型、および引数リスト)が含まれており、原則として、そのメソッドの機能を説明する各メソッドに対して十分なJavadocが必要です。インターフェースを使用する最も説得力のある理由は、インターフェースの複数の異なる実装を計画している場合、おそらくデプロイメント構成に応じて実装を選択することです。

対照的に、Java抽象クラスは、インターフェースを指定するという主な目的を持つのではなく、クラスの部分的な実装を提供します。複数のクラスがコードを共有する場合に使用する必要がありますが、サブクラスも実装の一部を提供することが期待される場合に使用します。これにより、実装の一部が抽象クラスに存在せず、サブクラスによって提供されることが期待されることを明確にしながら、共有コードを1つの場所(抽象クラ​​ス)にのみ表示できます。


0

あなたの答えは正しいですが、インタビュアーは、Javaの詳細に従ってではなく、ソフトウェアエンジニアリングの観点に従って区別する必要があります。

簡単な言葉:

インターフェースは、ショップに表示されるものはショップにあるショップのインターフェースに似ているため、インターフェイスのメソッドはすべて、具象クラスに実装する必要があります。次に、一部のクラスが正確なメソッドを共有し、他のクラスで異なる場合はどうなりますか。インターフェイスが2つのものを含むショップに関するものであり、2つのショップが両方ともスポーツ用品を持っているが、1つは衣服を追加し、もう1つは靴を追加しているとします。つまり、Sportsメソッドを実装するSportの抽象クラスを作成し、他のメソッドは実装しないままにします。ここでの抽象クラスは、このショップ自体は存在しないが、他のクラス/ショップのベースであることを意味します。このようにして、コードを整理し、コードの複製エラーを回避し、コードを統合し、他のクラスによる再利用性を保証します。

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