インタフェースと抽象クラスから

3775 ワード

面接のたびに、インタフェースと抽象クラスの違いは何ですか?この問題は簡単そうに見えますが、ネット上の答えもたくさん探しています.しかし、私は応募者が暗記した答えが欲しくありません.技術に熱中している人は、この問題を何度も繰り返し考えて、自分の見解を言うことができます.しかし、私を失望させたのは、私が満足している答えを得ることはめったにありません.この文章を書いて、インタフェースと抽象クラスに対する私の認識を分かち合います.
イメージ
  • インタフェースはinterfaceで宣言され、抽象クラスはclassで
  • で宣言されます.
  • インタフェースキーワードimplementsを実現し、抽象クラスキーワードextends
  • を継承する
    これらはすべて表象的なもので、言語の面でインタフェースと抽象類を区別したのです.
    abstractはprivate、static、finalまたはnativeと並列に同じ方法を修飾することはできません
    ここまで言うと、ついでにこのキーワードを見てみましょう.
    public protected deafult(デフォルト)private
    これらのキーワードは役割ドメインのキーワードです
  • publicこの方法またはフィールドは、すべてのユーザに対して
  • を開発する.
  • protectedこの方法またはフィールドは、自身に対して、同じパッケージの下のクラスに対して、サブクラスは
  • オープンである.
  • デフォルトこのメソッドまたはフィールドは、パケットの下のクラスに対して
  • オープンです.
  • privateこのメソッドまたはフィールドは、
  • のみを自分にオープンします.
    ps:ここには2つの点が混同される可能性があります.
  • protectedはデフォルトのデフォルトよりも広い
  • protectedメソッドとフィールドは、同じパッケージの下のクラスに対して開放することができ、protectedによって修飾されたのは、自分とサブクラスに対してのみ
  • 開放されていると考えている人もいる.
    final
  • finalクラスは継承できません.サブクラスはありません.finalクラスのメソッドのデフォルトはfinalの
  • です.
  • finalメソッドは布団類のメソッドで上書きすることはできないが、
  • を継承することができる.
  • finalメンバー変数は定数を表し、1回のみ付与され、付与後の値は
  • を変更しない.
  • finalは、構造方法
  • を修飾するために使用できない.
    インタフェースのすべての方法は抽象的であり,すなわち,インタフェースの方法はabstractによって暗黙的に修飾されている.したがって、インタフェースメソッドではtatic、final、nativeは表示されません.また、インタフェースのアクセス権はpublicです.
    インタフェースのフィールドはpublic static finalキーワード修飾です
  • インタフェースのフィールドは、宣言時に初期化されなければならない.これは、インタフェースのフィールドがfinalによって暗黙的に修飾されているためである.
  • 列挙
  • の代わりにインタフェースを使用しないでください.
    この問題は以前の分かち合いで述べたことがあるが,ここではこれ以上述べない.
    インタフェース定義タイプ
    単一継承とマルチインプリメンテーション
    この特性はインタフェースの重要な応用をもたらした:タイプを定義するために使用される.抽象クラスでタイプを定義する弊害を例に挙げます.
    たとえば、歌手のタイプと歌手のタイプを定義します.
    public interface SongWriter {
    void writeSong();
    }   
    
    public interface Singer {
    void singSong();
    }
    

    もし一人が、歌手でもあり、作曲家でもあり、三里屯のような人は珍しくないなら、この人はこのように定義することができます.
    public class SingerAndWriter implements Singer,SongWriter{
     @Override
     public void singSong() {
    
     }
    
     @Override
     public void writeSong() {
    
     }
    }   
    

    しかし、タイプを抽象クラスとして定義すると、抽象クラスがマルチ継承をサポートしないルールは、歌手が自分のために歌を書くことを制限します.
    この間、パートナーとこの問題について議論し、パートナーは解決策を提供しました.SingerAndWriterを書いて、SongWriterとSingerの引用を持たせて、このように歌いたいなら歌い、書きたいなら書きます.しかし、このようなデザインには大きな問題があります.本来SingerAndWriter is a SongWriterおよびSingerAndWriter is a Singerである.小さな仲間を採用すると、SingerAndWriter has a SongWriterとSingerAndWriter has a Singerになります.そうすると、機能が実現したように見えます.しかし、ある日私たちはコンサートを開くので、Singerを入参として伝える必要があります....冷や汗をかく!
    1つのクラスが複数のインタフェースを実装する際に問題が発生することを防止するために、インタフェースのメソッド名を繰り返すことはできません.
    インタフェースが複数実装可能であるため,クライアントが実装する2つのインタフェースに同じメソッド名がある場合,機能実装上の混乱や誤りをもたらす.このような問題が発生すると、結果は災難的になります.インタフェースという最上階のものは、往々にして一発で全身を動かすからだ.
    抽象クラスは多重化のため
    以下の説明はeffective javaから抜粋します
  • 抽象クラスは抽象クラスを多重化するための特徴の一つとして、非抽象的な方法を許可することである.継承はコード再利用を実現する有力な手段である.しかし、彼は永遠にこの仕事を完成する最善の手段ではない.子クラスとスーパークラスの間にサブタイプ関係が確かに存在する場合にのみ、継承を使用するのが適切です.それでも、サブクラスとスーパークラスが異なるパッケージにあり、スーパークラスが継承のために設計されていない場合、継承は脆弱性をもたらします.
  • 継承乱用防止、装飾モード
  • を使用してください.
    メソッド呼び出しとは異なり,継承はパッケージ性を破った.すなわち、サブクラスは、そのスーパークラスにおける特定の機能の実装の詳細に依存する.スーパークラスの実装は、リリースバージョンによって変化する可能性があり、コードが完全に変更されていなくても、サブクラスが破壊される可能性があります.したがって、サブクラスは、拡張のために設計され、良好なドキュメントの説明がない限り、サブクラスがそのスーパークラスの更新に伴って2つの進化を遂げなければならない.
    解決策:装飾モード.(「複合」)
    新しいクラスは古いクラスと同じインタフェースを実現し、新しいクラスは古いクラスの参照を持っています.
    新しいクラスの各インスタンスメソッドは、既存のクラスインスタンスを含む対応するメソッドを呼び出し、結果を返すことができます.このようにして得られたクラスは非常に安定しており、既存のクラスの実装の詳細に依存しません.既存のクラスに新しいメソッドが追加されても、新しいクラスには影響しません.
    包装類はほとんど欠点がありません.注意しなければならないのは、包装類がコールバックフレームに適していないことです.オブジェクトは、自身の参照を他のオブジェクトに渡し、後続のコールバックに使用します.包装されたオブジェクトは、彼の外の包装オブジェクトを知らないため、自身への参照(this)を伝え、コールバック時に外の包装オブジェクトを避けた.これをSELF問題と呼ぶ.
    転送メソッド呼び出しによるパフォーマンスの影響や、パッケージオブジェクトによるメモリの消費を懸念する人もいます.実践の中で、この2つは大きな影響を与えません.転送方法の作成は些細ですが、インタフェースごとにコンストラクタを1回作成するだけで、転送クラスはインタフェースを含むパッケージで提供できます.