-
Eine Schnittstelle beschreibt lediglich Verhalten. Er hat kein Vermögen. Aber eine abstrakte Klasse hat einen Zustand: Sie beschreibt beides.
Nehmen wir als Beispiel eine abstrakte Klasse
Bird
und SchnittstelleFlyable
: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; } }
Erstellen wir eine Vogelklasse
Mockingjay
(Mockingjay) und erben vonBird
:public class Mockingjay extends Bird { @Override public void fly() { System.out.println(„Flieg, Vögelchen!“); } public static void main(String[] args) { Mockingjay someBird = new Mockingjay(); someBird.setAge(19); System.out.println(someBird.getAge()); } }
Wie Sie sehen, können wir leicht auf den Status der abstrakten Klasse zugreifen – ihre Variablen
species
(Typ) undage
(Alter).Aber wenn wir versuchen, dasselbe mit der Schnittstelle zu machen, wird das Bild anders sein. Wir können versuchen, Variablen hinzuzufügen:
public interface Flyable { String species = new String(); int age = 10; public void fly(); } public interface Flyable { private String species = new String(); // Fehler private int age = 10; // auch ein Fehler public void fly(); }
Wir werden nicht einmal in der Lage sein, private Variablen innerhalb der Schnittstelle zu erstellen. Warum? Weil der private Modifikator erstellt wurde, um die Implementierung vor dem Benutzer zu verbergen. Aber es gibt keine Implementierung innerhalb der Schnittstelle: Es gibt dort nichts zu verbergen.
Die Schnittstelle beschreibt nur das Verhalten. Dementsprechend können wir Getter und Setter nicht innerhalb der Schnittstelle implementieren. Das liegt in der Natur einer Schnittstelle: Sie soll sich mit dem Verhalten befassen, nicht mit dem Zustand.
Java8 hat Standardschnittstellenmethoden eingeführt, die über eine Implementierung verfügen. Sie kennen sie bereits, daher werden wir sie nicht wiederholen.
-
Eine abstrakte Klasse verknüpft und vereint Klassen, die eine sehr enge Beziehung zueinander haben. Gleichzeitig kann dieselbe Schnittstelle durch Klassen implementiert werden, die überhaupt nichts gemeinsam haben.
Kehren wir zu unserem Beispiel mit Vögeln zurück.
Unsere abstrakte Klasse
Bird
wird benötigt, um darauf basierende Vögel zu erstellen. Nur Vögel und sonst niemand! Natürlich werden sie unterschiedlich sein.Bei der Schnittstelle
Flyable
ist alles anders. Es beschreibt nur das Verhalten, das seinem Namen entspricht – „Fliegen“. Die Definition von „fliegend“, „flugfähig“ umfasst viele Objekte, die nicht miteinander in Zusammenhang stehen.Diese 4 Einheiten sind in keiner Weise miteinander verbunden. Was soll ich sagen, nicht alle davon sind überhaupt belebt. Sie sind jedoch alle
Flyable
flugfähig.Wir könnten sie nicht mit einer abstrakten Klasse beschreiben. Sie haben keinen gemeinsamen Zustand oder identische Felder. Um ein Flugzeug zu charakterisieren, benötigen wir voraussichtlich die Felder „Modell“, „Baujahr“ und „maximale Passagierzahl“. Für Carlson gibt es Felder für alle Süßigkeiten, die er heute gegessen hat, und eine Liste von Spielen, die er mit dem Kind spielen wird. Für eine Mücke ... ähm ... wir wissen es nicht einmal ... Vielleicht „Belästigungsgrad“? :) :)
Die Hauptsache ist, dass wir sie nicht mit einer abstrakten Klasse beschreiben können. Sie sind zu unterschiedlich. Aber es gibt ein gemeinsames Verhalten: Sie können fliegen. Die Schnittstelle ist ideal, um alles auf der Welt zu beschreiben, was fliegen, schwimmen, springen oder ein anderes Verhalten zeigen kann.
-
Klassen können beliebig viele Schnittstellen implementieren, aber nur von einer Klasse erben.
Darüber haben wir bereits mehr als einmal gesprochen. In Java gibt es keine Mehrfachvererbung, aber eine Mehrfachimplementierung. Dieser Punkt folgt teilweise aus dem vorherigen: Eine Schnittstelle verbindet viele verschiedene Klassen, die oft nichts gemeinsam haben, und eine abstrakte Klasse wird für eine Gruppe von Klassen erstellt, die sehr nahe beieinander liegen. Daher ist es logisch, dass Sie nur von einer solchen Klasse erben können. Eine abstrakte Klasse beschreibt die „ist ein“-Beziehung.
Standard-InputStream- und OutputStream-Schnittstellen
Wir haben bereits die verschiedenen Klassen durchgegangen, die für die Streaming-Eingabe und -Ausgabe verantwortlich sind. Schauen wir uns anInputStream
und OutputStream
. Im Allgemeinen handelt es sich hierbei nicht um Schnittstellen, sondern um echte abstrakte Klassen. Jetzt wissen Sie, was sie sind, sodass die Arbeit mit ihnen viel einfacher wird :) InputStream
- Dies ist eine abstrakte Klasse, die für die Byte-Eingabe verantwortlich ist. Java verfügt über eine Reihe von Klassen, die von erben InputStream
. Jeder von ihnen ist so konfiguriert, dass er Daten aus verschiedenen Quellen empfängt. Da InputStream
es sich um ein übergeordnetes Element handelt, bietet es mehrere Methoden zum bequemen Arbeiten mit Datenströmen. Jedes Kind hat diese Methoden InputStream
:
int available()
gibt die Anzahl der zum Lesen verfügbaren Bytes zurück;close()
schließt die Eingabequelle;int read()
gibt eine ganzzahlige Darstellung des nächsten verfügbaren Bytes im Stream zurück. Wenn das Ende des Streams erreicht ist, wird die Zahl -1 zurückgegeben;int read(byte[] buffer)
versucht, Bytes in einen Puffer zu lesen und gibt die Anzahl der gelesenen Bytes zurück. Wenn das Ende der Datei erreicht ist, wird -1 zurückgegeben.int read(byte[] buffer, int byteOffset, int byteCount)
liest einen Teil eines Byteblocks. Wird verwendet, wenn die Möglichkeit besteht, dass der Datenblock nicht vollständig gefüllt wurde. Wenn das Ende der Datei erreicht ist, wird -1 zurückgegeben.long skip(long byteCount)
überspringtbyteCount
ein Byte der Eingabe und gibt die Anzahl der ignorierten Bytes zurück.
FileInputStream
: der häufigste TypInputStream
. Wird zum Lesen von Informationen aus einer Datei verwendet.StringBufferInputStream
: ein weiterer nützlicher TypInputStream
. Es wandelt eine Zeichenfolge in einen Eingabedatenstrom umInputStream
.BufferedInputStream
: gepufferter Eingabestream. Es wird am häufigsten zur Verbesserung der Effizienz eingesetzt.
BufferedReader
und sagten, dass wir es nicht benutzen müssen? Wenn wir schreiben:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
... BufferedReader
Sie müssen es nicht verwenden: InputStreamReader
Es wird den Zweck erfüllen. Aber BufferedReader
es macht das effizienter und kann darüber hinaus Daten in ganzen Zeilen statt einzelner Zeichen lesen. Alles BufferedInputStream
ist das selbe! Die Klasse sammelt Eingabedaten in einem speziellen Puffer, ohne ständig auf das Eingabegerät zuzugreifen. Schauen wir uns ein Beispiel an:
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(„Charakter wurde gelesen“ + c);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
inputStream.close();
buffer.close();
}
}
}
In diesem Beispiel lesen wir Daten aus einer Datei, die sich auf dem Computer unter der Adresse „D:/Users/UserName/someFile.txt“ befindet . Wir erstellen 2 Objekte – FileInputStream
und BufferedInputStream
zwar als deren „Hülle“. Danach lesen wir die Bytes aus der Datei und wandeln sie in Zeichen um. Und so weiter, bis die Datei zu Ende ist. Wie Sie sehen, gibt es hier nichts Kompliziertes. Sie können diesen Code kopieren und in einer echten Datei ausführen, die auf Ihrem Computer gespeichert ist :) Eine Klasse OutputStream
ist eine abstrakte Klasse, die eine Byte-Stream-Ausgabe definiert. Wie Sie bereits verstehen, ist dies der Antipode von InputStream
„a“. Es ist nicht dafür verantwortlich, woher Daten gelesen werden, sondern dafür, wohin sie gesendet werden . Diese abstrakte Klasse stellt allen Nachkommen eine InputStream
Gruppe von Methoden zur bequemen Arbeit zur Verfügung:
int close()
schließt den Ausgabestream;void flush()
löscht alle Ausgabepuffer;abstract void write (int oneByte)
schreibt 1 Byte in den Ausgabestream;void write (byte[] buffer)
schreibt ein Array von Bytes in den Ausgabestream;void write (byte[] buffer, int offset, int count)
schreibt einen Bereich von Zählbytes aus dem Array, beginnend beim Positionsoffset.
OutputStream
:
-
DataOutputStream
. Ein Ausgabestream, der Methoden zum Schreiben von Standard-Java-Datentypen enthält.Eine sehr einfache Klasse zum Schreiben primitiver Java-Typen und -Strings. Sicherlich werden Sie den geschriebenen Code auch ohne Erklärung verstehen:
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); } }
Für jeden Typ gibt es separate Methoden –
writeDouble()
,writeLong()
usw.writeShort()
-
Klasse
FileOutputStream
. Implementiert einen Mechanismus zum Senden von Daten an eine Datei auf der Festplatte. Wir haben es übrigens bereits im vorherigen Beispiel verwendet, ist Ihnen das aufgefallen? Wir haben es innerhalb des DataOutputStream übergeben, der als „Wrapper“ fungierte. -
BufferedOutputStream
. Gepufferter Ausgabestream. Auch nichts Kompliziertes, das Wesentliche ist dasselbe wie inBufferedInputStream
(oderBufferedReader
'a). Anstelle der üblichen sequentiellen Datenaufzeichnung wird die Aufzeichnung über einen speziellen „Speicher“-Puffer verwendet. Durch die Verwendung eines Puffers können Sie die Anzahl der Roundtrips zum Datenziel reduzieren und dadurch die Effizienz verbessern.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!"; // Wir werden diesen String in ein Array von Bytes konvertieren und in eine Datei schreiben byte[] buffer = text.getBytes(); bufferedStream.write(buffer, 0, buffer.length); bufferedStream.close(); } }
Auch hier können Sie selbst mit diesem Code „spielen“ und prüfen, wie er mit echten Dateien auf Ihrem Computer funktioniert.
InputStream
Ein- /Ausgabesystem “ nachlesen. Oh , und wir werden auch einen separaten Vortrag halten, sodass für das erste Kennenlernen genügend Informationen darüber vorhanden sind. Das ist alles! Wir hoffen, dass Sie die Unterschiede zwischen Schnittstellen und abstrakten Klassen gut verstehen und bereit sind, jede Frage zu beantworten, auch eine knifflige :) OutputStream
FileInputStream
FileOutputStream
BufferedInputStream
GO TO FULL VERSION