JavaRush /Java Blog /Random-JA /抽象クラスとインターフェイスの違い

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

Random-JA グループに公開済み
こんにちは!この講義では、抽象クラスがインターフェイスとどのように異なるかについて説明し、一般的な抽象クラスの例を見ていきます。 抽象クラスとインターフェイスの違い - 1このトピックは非常に重要であるため、抽象クラスとインターフェイスの違いについては別の講義に充てました。今後の面接の 90% で、これらの概念の違いについて質問されることになります。したがって、読んだ内容を必ず理解し、何かが完全に理解できない場合は、追加のソースを読んでください。したがって、抽象クラスとは何か、インターフェイスとは何かはわかりました。次に、それらの違いを見てみましょう。
  1. インターフェースは動作のみを記述します。彼には財産がありません。しかし、抽象クラスには状態があり、両方を記述します。

    例として抽象クラスBirdとインターフェイスを取り上げてみましょうFlyable

    public abstract class Bird {
       private String species;
       private int age;
    
       public abstract void fly();
    
       public String getSpecies() {
           return species;
       }
    
       public void setSpecies(String species) {
           this.species = species;
       }
    
       public int getAge() {
           return age;
       }
    
       public void setAge(int age) {
           this.age = age;
       }
    }

    鳥クラスMockingjay(モッキングジェイ) を作成し、以下から継承しましょうBird

    public class Mockingjay extends Bird {
    
       @Override
       public void fly() {
           System.out.println("Fly, birdie!");
       }
    
       public static void main(String[] args) {
    
           Mockingjay someBird = new Mockingjay();
           someBird.setAge(19);
           System.out.println(someBird.getAge());
       }
    }

    ご覧のとおり、抽象クラスの状態、つまり変数species(type) とage(age) に簡単にアクセスできます。

    しかし、インターフェースで同じことをやろうとすると、状況は異なります。それに変数を追加してみることができます。

    public interface Flyable {
    
       String species = new String();
       int age = 10;
    
       public void fly();
    }
    
    public interface Flyable {
    
       private String species = new String(); // error
       private int age = 10; // also an error
    
       public void fly();
    }

    インターフェイス内にプライベート変数を作成することもできません。なぜ?private修飾子は実装をユーザーから隠すために作成されたためです。しかし、インターフェイス内には実装はありません。そこには隠すものは何もありません。

    インターフェイスでは動作のみが説明されています。したがって、インターフェース内にゲッターとセッターを実装することはできません。これがインターフェイスの性質です。インターフェイスは状態ではなく動作を処理することを目的としています。

    Java8 では、実装されたデフォルトのインターフェイス メソッドが導入されました。それらについてはすでにご存知なので、繰り返しません。

  2. 抽象クラスは、非常に密接な関係を持つクラスをリンクして結合します。同時に、まったく共通点のないクラスによって同じインターフェイスを実装することもできます。

    鳥の例に戻りましょう。

    抽象クラスは、Birdそれに基づいて鳥を作成するために必要です。鳥だけで他には誰もいません!もちろん、それらは異なるでしょう。

    抽象クラスとインターフェイスの違い - 2

    インターフェースに関しては、Flyableすべてが異なります。「飛行」という名前に対応する動作のみを説明します。「飛行」「飛行可能」の定義には、互いに関連性のない多くの物体が含まれます。

    抽象クラスとインターフェイスの違い - 3

    これら 4 つのエンティティは互いにまったく関連しません。何と言うか、それらすべてが生きているわけではありません。ただし、それらはすべてFlyable飛行可能です。

    抽象クラスを使用してそれらを記述することはできません。これらには共通の状態や同一のフィールドはありません。航空機を特徴付けるには、おそらく「モデル」、「製造年」、「最大乗客数」のフィールドが必要になります。カールソンの場合は、今日食べたすべてのお菓子のフィールドと、キッドとプレイするゲームのリストがあります。蚊の場合は...うーん...私たちにもわかりません...おそらく「迷惑レベル」でしょうか?:)

    重要なことは、抽象クラスを使用してそれらを記述することができないということです。違いすぎます。しかし、共通の行動があります。それは、彼らは飛ぶことができるということです。このインターフェイスは、飛んだり、泳いだり、ジャンプしたり、その他の動作をする世界のあらゆるものを記述するのに最適です。

  3. クラスは必要なだけインターフェイスを実装できますが、継承できるクラスは 1 つだけです。

    これについてはすでに何度か話しました。Java には多重継承はありませんが、複数の実装があります。この点は、前の点から部分的に踏襲されています。インターフェースは、多くの場合、共通点のない多くの異なるクラスを接続し、抽象クラスは、互いに非常に近いクラスのグループに対して作成されます。したがって、そのようなクラスを 1 つだけ継承できるのは論理的です。抽象クラスは、「である」関係を記述します。

標準のInputStreamおよびOutputStreamインターフェイス

ストリーミング入力と出力を担当するさまざまなクラスについてはすでに説明しました。InputStreamと を見てみましょうOutputStream。一般に、これらはインターフェイスではなく、実際の抽象クラスです。これで、それらが何であるかがわかったので、それらを扱うのがはるかに簡単になります:) InputStream- これはバイト入力を担当する抽象クラスです。Java には、 を継承する一連のクラスがありますInputStream。それらはそれぞれ、異なるソースからデータを受信するように構成されています。InputStreamこれは親であるため、データ ストリームを便利に操作するためのメソッドをいくつか提供します。各子には次のメソッドがありますInputStream
  • int available()読み取り可能なバイト数を返します。
  • close()入力ソースを閉じます。
  • int read()ストリーム内で次に利用可能なバイトの整数表現を返します。ストリームの終わりに到達すると、数値 -1 が返されます。
  • int read(byte[] buffer)バッファにバイトを読み取ろうとし、読み取られたバイト数を返します。ファイルの終わりに達すると -1 を返します。
  • int read(byte[] buffer, int byteOffset, int byteCount)バイトのブロックの一部を読み取ります。データブロックが完全に埋まっていない可能性がある場合に使用されます。ファイルの終わりに達すると -1 を返します。
  • long skip(long byteCount)入力バイトをスキップしbyteCount、無視されたバイト数を返します。
メソッドの全リスト を研究することをお勧めします。実際には十数の後継クラスがあります。以下にいくつかの例を示します。
  1. FileInputStream: 最も一般的なタイプInputStream。ファイルから情報を読み取るために使用されます。
  2. StringBufferInputStream: もう 1 つの便利なタイプInputStream。文字列を入力データ ストリームに変換しますInputStream
  3. BufferedInputStream: バッファリングされた入力ストリーム。効率を向上させるために最もよく使用されます。
私たちが通りかかってBufferedReader、それを使う必要はないと言ったときのことを覚えていますか? 書くとき:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
...BufferedReader使用する必要はありません。InputStreamReader機能します。しかし、BufferedReaderそれはより効率的に行われ、さらに、個々の文字ではなく行全体でデータを読み取ることができます。すべてがBufferedInputStream同じです!このクラスは、入力デバイスに常にアクセスすることなく、入力データを特別なバッファーに蓄積します。例を見てみましょう:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;

public class BufferedInputExample {

   public static void main(String[] args) throws Exception {
       InputStream inputStream = null;
       BufferedInputStream buffer = null;

       try {

           inputStream = new FileInputStream("D:/Users/UserName/someFile.txt");

           buffer = new BufferedInputStream(inputStream);

           while(buffer.available()>0) {

               char c = (char)buffer.read();

               System.out.println("Character was read" + c);
           }
       } catch(Exception e) {

           e.printStackTrace();

       } finally {

           inputStream.close();
           buffer.close();
       }
   }
}
この例では、コンピューター上のアドレス"D:/Users/UserName/someFile.txt" にあるファイルからデータを読み取ります。2 つのオブジェクトを作成し、その「ラッパー」として作成しFileInputStreamますBufferedInputStream。その後、ファイルからバイトを読み取り、文字に変換します。ファイルが終了するまで続きます。ご覧のとおり、ここでは複雑なことは何もありません。このコードをコピーして、コンピュータに保存されている実際のファイル上で実行できます :) クラスは、OutputStreamバイト ストリーム出力を定義する抽象クラスです。すでに理解されているように、これは「a」の対蹠子ですInputStreamデータをどこから読み取るかではなく、データをどこに送信するかを担当します。と同様InputStream、この抽象クラスはすべての子孫に便利な作業のためのメソッドのグループを提供します。
  • int close()出力ストリームを閉じます。
  • void flush()すべての出力バッファをクリアします。
  • abstract void write (int oneByte)出力ストリームに 1 バイトを書き込みます。
  • void write (byte[] buffer)バイト配列を出力ストリームに書き込みます。
  • void write (byte[] buffer, int offset, int count)位置オフセットから開始して、配列から count バイトの範囲を書き込みます。
以下にクラスの子孫の一部を示しますOutputStream
  1. DataOutputStream。標準 Java データ型を記述するためのメソッドを含む出力ストリーム。

    プリミティブ Java 型と文字列を記述するための非常に単純なクラス。説明がなくても、書かれたコードを理解できるはずです。

    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           DataOutputStream dos = new DataOutputStream(new FileOutputStream("testFile.txt"));
    
           dos.writeUTF("SomeString");
           dos.writeInt(22);
           dos.writeDouble(1.21323);
           dos.writeBoolean(true);
    
       }
    }

    タイプごとに個別のメソッド ( 、writeDouble()など) があります。writeLong()writeShort()

  2. クラス FileOutputStream。ディスク上のファイルにデータを送信するメカニズムを実装します。ところで、前の例ですでに使用しましたが、気づきましたか? これを「ラッパー」として機能する DataOutputStream 内に渡しました。

  3. BufferedOutputStream。バッファリングされた出力ストリーム。BufferedInputStream何も複雑なことはなく、本質は(またはBufferedReader'a)と同じです。通常のシーケンシャルデータ記録の代わりに、特別な「ストレージ」バッファを介した記録が使用されます。バッファを使用すると、データの宛先までの往復回数が減り、効率が向上します。

    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           FileOutputStream outputStream = new FileOutputStream("D:/Users/Username/someFile.txt");
           BufferedOutputStream bufferedStream = new BufferedOutputStream(outputStream);
    
           String text = "I love Java!"; // we will convert this string into an array of bytes and write it to a file
    
           byte[] buffer = text.getBytes();
    
           bufferedStream.write(buffer, 0, buffer.length);
           bufferedStream.close();
       }
    }

    繰り返しますが、このコードを自分で「試して」、コンピュータ上の実際のファイルでどのように動作するかを確認することができます。

相続人については資料「入出力システム」でもご覧InputStreamいただけます。あ、別途講座もございますので、初対面の方には十分な内容となっております。それだけです!インターフェースと抽象クラスの違いをよく理解し、たとえ難しい質問であっても、どんな質問にも答える準備ができていることを願っています :) OutputStreamFileInputStreamFileOutputStreamBufferedInputStream
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION