Für die objektorientierte Programmierung ist die Abstraktion eines ihrer Hauptmerkmale. In Java kann die Abstraktion der OOP in zwei Formen verkörpert werden:Schnittstellen und abstrakte Klassen.Zwischen den beiden gibt es viele Ähnlichkeiten und auch viele Unterschiede. Viele Anfänger denken, sie könnten austauschbar verwendet werden, aber tatsächlich ist das nicht der Fall. Lassen Sie uns heute gemeinsam etwas über Schnittstellen und abstrakte Klassen in Java lernen.


1. Abstrakte Klassen

Bevor wir abstrakte Klassen verstehen, wollen wir zunächst abstrakte Methoden verstehen. Eine abstrakte Methode ist eine spezielle Methode: Sie hat nur eine Deklaration, aber keine konkrete Implementierung. Das Deklarationsformat einer abstrakten Methode ist:

abstract void fun();

Abstrakte Methoden müssen mit dem Schlüsselwort abstract modifiziert werden. Wenn eine Klasse eine abstrakte Methode enthält, wird sie als abstrakte Klasse bezeichnet, und die abstrakte Klasse muss vor der Klasse mit dem Schlüsselwort abstract modifiziert werden. Da eine abstrakte Klasse Methoden ohne konkrete Implementierung enthält, können Sie keine Objekte aus einer abstrakten Klasse erstellen.

Beachten Sie Folgendes: In dem Buch „Thinking in Java“ wird eine abstrakte Klasse als „eine Klasse, die abstrakte Methoden enthält“ definiert, aber später stellte sich heraus, dass, wenn eine Klasse keine abstrakten Methoden enthält und nur mit abstract modifiziert wird, sie ebenfalls eine abstrakte Klasse ist. Das heißt, eine abstrakte Klasse muss nicht unbedingt abstrakte Methoden enthalten. Persönlich halte ich dies für eine pedantische Frage, denn wenn eine abstrakte Klasse keine abstrakten Methoden enthält, warum sollte man sie dann als abstrakte Klasse entwerfen? Merken Sie sich dieses Konzept also vorerst einfach, und es ist nicht nötig, der Frage nachzugehen, warum.

[public] abstract class ClassName {
    abstract void fun();
}

Daraus ist ersichtlich, dass abstrakte Klassen für die Vererbung existieren. Wenn Sie eine abstrakte Klasse definieren, sie aber nicht erben, dann haben Sie die abstrakte Klasse vergeblich erstellt, weil Sie sie nicht für irgendetwas verwenden können. Für eine Elternklasse, wenn eine ihrer Methoden bei der Implementierung in der Elternklasse keinen Sinn ergibt und je nach den tatsächlichen Bedürfnissen der Unterklassen unterschiedlich implementiert werden muss, dann kann diese Methode als abstrakte Methode deklariert werden, und an diesem Punkt wird die Klasse auch zu einer abstrakten Klasse.

Eine Klasse, die abstrakte Methoden enthält, wird als abstrakte Klasse bezeichnet, aber das bedeutet nicht, dass eine abstrakte Klasse nur abstrakte Methoden haben kann. Wie eine gewöhnliche Klasse kann sie auch Mitgliedsvariablen und gewöhnliche Mitgliedsmethoden haben. Beachten Sie, dass es drei Hauptunterschiede zwischen abstrakten Klassen und gewöhnlichen Klassen gibt:

  • 1) Abstrakte Methoden müssen public oder protected sein (denn wenn sie private sind, können sie nicht von Unterklassen geerbt werden, und Unterklassen werden nicht in der Lage sein, sie zu implementieren). Standardmäßig sind sie public.
  • 2) Abstrakte Klassen können nicht zum Erstellen von Objekten verwendet werden;
  • 3) Wenn eine Klasse von einer abstrakten Klasse erbt, muss die Unterklasse die abstrakten Methoden der Elternklasse implementieren. Wenn die Unterklasse die abstrakten Methoden der Elternklasse nicht implementiert, muss die Unterklasse auch als abstrakte Klasse definiert werden.
  • In anderer Hinsicht unterscheiden sich abstrakte Klassen nicht von gewöhnlichen Klassen.

2. Schnittstellen

Eine Schnittstelle, im Englischen "interface" genannt, bezieht sich in der Softwaretechnik im Allgemeinen auf Methoden oder Funktionen, die anderen zur Verfügung gestellt werden, damit sie sie aufrufen können. Daraus können wir die ursprüngliche Absicht der Java-Sprachdesigner erkennen: Es ist eine Abstraktion von Verhalten. In Java ist die Form zur Definition einer Schnittstelle wie folgt:

[public] interface InterfaceName {
 
}

Schnittstellen können Variablen und Methoden enthalten. Beachten Sie jedoch, dass Variablen in einer Schnittstelle implizit als public static final Variablen spezifiziert sind (und nur public static final Variablen sein können; die Verwendung von private führt zu einem Kompilierungsfehler), während Methoden implizit als public abstract Methoden spezifiziert sind und nur public abstract Methoden sein können (die Verwendung anderer Schlüsselwörter wie private, protected, static, final usw. führt zu einem Kompilierungsfehler). Außerdem darf keine der Methoden in einer Schnittstelle eine konkrete Implementierung haben; das heißt, alle Methoden in einer Schnittstelle müssen abstrakte Methoden sein. Daran können wir vage den Unterschied zwischen Schnittstellen und abstrakten Klassen erkennen. Eine Schnittstelle ist ein extrem abstrakter Typ; sie ist „abstrakter“ als eine abstrakte Klasse, und Variablen werden in einer Schnittstelle im Allgemeinen nicht definiert.

Um eine Klasse eine bestimmte Menge von Schnittstellen implementieren zu lassen, müssen Sie das Schlüsselwort implements verwenden. Das konkrete Format ist wie folgt:

class ClassName implements Interface1,Interface2,[....]{
}

Es ist ersichtlich, dass eine Klasse mehrere bestimmte Schnittstellen implementieren darf. Wenn eine nicht-abstrakte Klasse eine Schnittstelle implementiert, muss sie alle Methoden in dieser Schnittstelle implementieren. Bei einer abstrakten Klasse, die eine Schnittstelle implementiert, muss sie die abstrakten Methoden in dieser Schnittstelle nicht unbedingt implementieren.


Unterschiede zwischen abstrakten Klassen und Schnittstellen

1. Syntaktische Unterschiede

  • 1) Abstrakte Klassen können Implementierungsdetails von Member-Methoden bereitstellen, während Schnittstellen nur public abstract Methoden haben können;
  • 2) Member-Variablen in abstrakten Klassen können verschiedene Typen haben, während Member-Variablen in Schnittstellen nur vom Typ public static final sein können;
  • 3) Schnittstellen können keine statischen Codeblöcke oder statischen Methoden enthalten, während abstrakte Klassen statische Codeblöcke und statische Methoden haben können;
  • 4) Eine Klasse kann nur von einer abstrakten Klasse erben, aber eine Klasse kann mehrere Schnittstellen implementieren.

2. Unterschiede auf Designebene

1) Eine abstrakte Klasse ist eine Abstraktion einer Art von Ding, das heißt eine Abstraktion einer Klasse, während eine Schnittstelle eine Abstraktion von Verhalten ist. Eine abstrakte Klasse abstrahiert die gesamte Klasse als Ganzes, einschließlich Attribute und Verhaltensweisen, aber eine Schnittstelle abstrahiert nur einen Teil einer Klasse (Verhalten). Ein einfaches Beispiel: Flugzeuge und Vögel sind verschiedene Arten von Dingen, aber sie teilen ein gemeinsames Merkmal: Sie können beide fliegen. Beim Entwurf können Sie das Flugzeug als Klasse Airplane und den Vogel als Klasse Bird entwerfen, aber Sie können nichtFliegenals eine Klasse behandeln, weil es nur ein Verhaltensmerkmal ist, keine abstrakte Beschreibung einer Art von Ding. An diesem Punkt können Sie Fliegen als Schnittstelle Fly entwerfen, die die Methode fly() enthält, und dann implementieren Airplane und Bird die Schnittstelle Fly nach ihren eigenen Bedürfnissen. Was verschiedene Arten von Flugzeugen betrifft, wie Kampfjets und Zivilflugzeuge, können sie direkt von Airplane erben. Ähnlich bei Vögeln: Verschiedene Vogelarten können direkt von der Klasse Bird erben. Daraus können wir ersehen, dass Vererbung eine „Ist-ein“-Beziehung ist, während Schnittstellenimplementierung eine „Hat-ein“-Beziehung ist. Wenn eine Klasse von einer abstrakten Klasse erbt, dann muss die Unterklasse eine Art der abstrakten Klasse sein, während es bei der Schnittstellenimplementierung darum geht, ob sie eine bestimmte Fähigkeit hat oder besitzt. Zum Beispiel, ob ein Vogel fliegen kann (oder ob er die Eigenschaft des Fliegens besitzt); wenn er fliegen kann, kann er diese Schnittstelle implementieren, wenn er nicht fliegen kann, implementiert er diese Schnittstelle nicht.

2) Die Entwurfsebenen sind unterschiedlich. Eine abstrakte Klasse als Elternklasse vieler Unterklassen ist ein vorlagenbasiertes Design. Eine Schnittstelle ist eine Verhaltensspezifikation, ein radiales Design. Was ist vorlagenbasiertes Design? Das einfachste Beispiel ist, dass jeder schon einmal Vorlagen in PPT verwendet hat. Wenn ppt B und ppt C unter Verwendung von Vorlage A entworfen werden, ist der gemeinsame Teil von ppt B und ppt C Vorlage A. Wenn ihr gemeinsamer Teil geändert werden muss, müssen Sie nur Vorlage A ändern, und ppt B und ppt C müssen nicht erneut geändert werden. Radiales Design, zum Beispiel: Wenn ein bestimmter Aufzug mit einem bestimmten Alarm ausgestattet ist, müssen bei einer Aktualisierung des Alarms alle aktualisiert werden. Das heißt, bei einer abstrakten Klasse können Sie, wenn Sie eine neue Methode hinzufügen müssen, direkt eine konkrete Implementierung in der abstrakten Klasse hinzufügen, und Unterklassen müssen nicht geändert werden; bei einer Schnittstelle ist das jedoch nicht der Fall. Wenn sich die Schnittstelle ändert, müssen alle Klassen, die die Schnittstelle implementieren, entsprechend geändert werden.

Unten ist das im Internet am weitesten verbreitete Beispiel: das Beispiel von Türen und Alarmen: Alle Türen habenopen()undclose()zwei Aktionen. An diesem Punkt können wir dieses abstrakte Konzept durch abstrakte Klassen und Schnittstellen definieren:

abstract class Door { public abstract void open(); public abstract void close(); }

Oder:

interface Door { public abstract void open(); public abstract void close(); }

Aber wenn wir nun möchten, dass die Tür eine Alarmfunktion hat, wie sollen wir das implementieren? Im Folgenden werden zwei Ansätze vorgestellt:

1) Alle drei Funktionen in die abstrakte Klasse aufnehmen, aber auf diese Weise haben alle von dieser abstrakten Klasse erbenden Unterklassen die Alarmfunktion, obwohl einige Türen nicht unbedingt eine Alarmfunktion haben müssen;

2) Alle drei Funktionen in die Schnittstelle aufnehmen. Eine Klasse, die die Alarmfunktion benötigt, müsste dann das open() und close() in dieser Schnittstelle implementieren, aber möglicherweise hat diese Klasse überhaupt keine open()- und close()-Funktionen, wie ein Feueralarm.

Daraus ist ersichtlich, dass open(), close() und alarm() von Door tatsächlich zu Verhaltensweisen in zwei unterschiedlichen Kategorien gehören. open() und close() sind inhärente Verhaltensmerkmale der Tür selbst, während alarm() ein erweitertes zusätzliches Verhalten ist. Daher ist die beste Lösung, alarm separat als Schnittstelle zu entwerfen, die das alarm()-Verhalten enthält, und Door als separate abstrakte Klasse zu entwerfen, die die beiden Verhaltensweisen open und close enthält. Dann entwirft man eine Klasse AlarmDoor, die von der Klasse Door erbt und die Schnittstelle Alarm implementiert.

interface Alram { void alarm(); } abstract class Door { void open(); void close(); } class AlarmDoor extends Door implements Alarm { void oepn() { //.... } void close() { //.... } void alarm() { //.... } }

Originaladresse: http://www.cnblogs.com/dolphin0520/p/3811437.html