インタフェースと抽象クラスから
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によって暗黙的に修飾されているためである. 列挙 の代わりにインタフェースを使用しないでください.
この問題は以前の分かち合いで述べたことがあるが,ここではこれ以上述べない.
インタフェース定義タイプ
単一継承とマルチインプリメンテーション
この特性はインタフェースの重要な応用をもたらした:タイプを定義するために使用される.抽象クラスでタイプを定義する弊害を例に挙げます.
たとえば、歌手のタイプと歌手のタイプを定義します.
もし一人が、歌手でもあり、作曲家でもあり、三里屯のような人は珍しくないなら、この人はこのように定義することができます.
しかし、タイプを抽象クラスとして定義すると、抽象クラスがマルチ継承をサポートしないルールは、歌手が自分のために歌を書くことを制限します.
この間、パートナーとこの問題について議論し、パートナーは解決策を提供しました.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回作成するだけで、転送クラスはインタフェースを含むパッケージで提供できます.
イメージ
これらはすべて表象的なもので、言語の面でインタフェースと抽象類を区別したのです.
abstractはprivate、static、finalまたはnativeと並列に同じ方法を修飾することはできません
ここまで言うと、ついでにこのキーワードを見てみましょう.
public protected deafult(デフォルト)private
これらのキーワードは役割ドメインのキーワードです
ps:ここには2つの点が混同される可能性があります.
final
インタフェースのすべての方法は抽象的であり,すなわち,インタフェースの方法はabstractによって暗黙的に修飾されている.したがって、インタフェースメソッドではtatic、final、nativeは表示されません.また、インタフェースのアクセス権はpublicです.
インタフェースのフィールドはpublic static 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回作成するだけで、転送クラスはインタフェースを含むパッケージで提供できます.