Hallo! In früheren Vorlesungen
haben wir uns mit Schnittstellen vertraut gemacht und herausgefunden, wofür sie benötigt werden. Das heutige Thema wird etwas mit dem vorherigen gemeinsam haben. Lassen Sie uns über
abstrakte Klassen in Java sprechen.
Warum heißen Klassen „abstrakt“?
Sie erinnern sich wahrscheinlich daran, was „Abstraktion“ ist – wir haben es bereits behandelt :) Wenn Sie es plötzlich vergessen haben, ist es in Ordnung, denken wir daran:
Dies ist das Prinzip von OOP , nach dem beim Entwerfen von Klassen und Erstellen von Objekten Hervorhebung erforderlich ist nur die Haupteigenschaften einer Entität und verwerfen die sekundären. Wenn wir beispielsweise eine Klasse entwerfen
SchoolTeacher
– einen Schullehrer –, ist es unwahrscheinlich, dass wir das Merkmal „
Größe “ benötigen. Tatsächlich: Für einen Lehrer ist diese Eigenschaft nicht wichtig. Wenn wir jedoch eine Klasse im Programm erstellen
BasketballPlayer
– einen Basketballspieler –, wird die
Körpergröße zu einem der Hauptmerkmale.
Eine abstrakte Klasse ist also das abstrakteste, ach so annähernd „leer“ für eine Gruppe zukünftiger Klassen. Dieses Präparat kann nicht in fertiger Form verwendet werden, es ist zu „roh“. Es beschreibt jedoch einen bestimmten allgemeinen Zustand und ein bestimmtes Verhalten, das zukünftige Klassen – Erben der abstrakten Klasse – haben werden.
Beispiele für abstrakte Java-Klassen
Schauen wir uns ein einfaches Beispiel mit Autos an:
public abstract class Car {
private String model;
private String color;
private int maxSpeed;
public abstract void gas();
public abstract void brake();
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
}
So sieht die einfachste abstrakte Klasse aus. Wie Sie sehen, nichts Besonderes :) Wofür könnten wir es brauchen? Zunächst beschreibt er auf möglichst abstrakte Weise die Entität, die wir brauchen – ein Auto. Das Wort
„abstrakt“ gibt es hier aus einem bestimmten Grund. Es gibt keine „gerechten Maschinen“ auf der Welt. Es gibt Lastwagen, Rennwagen, Limousinen, Coupés und SUVs.
Unsere abstrakte Klasse ist lediglich eine „Blaupause“, aus der wir später Autoklassen erstellen werden.
public class Sedan extends Car {
@Override
public void gas() {
System.out.println(„Die Limousine beschleunigt!“);
}
@Override
public void brake() {
System.out.println(„Die Limousine wird langsamer!“);
}
}
Das ähnelt stark dem, worüber wir in den Vorlesungen über Vererbung gesprochen haben. Nur dort hatten wir eine Klasse
Car
und ihre Methoden, die nicht abstrakt waren. Diese Lösung weist jedoch eine Reihe von Nachteilen auf, die in abstrakten Klassen behoben werden. Erstens
kann keine Instanz einer abstrakten Klasse erstellt werden:
public class Main {
public static void main(String[] args) {
Car car = new Car();
}
}
Dieser „Trick“ wurde speziell von den Java-Entwicklern implementiert. Noch einmal zur Erinnerung:
Eine abstrakte Klasse ist nur eine Blaupause für zukünftige „normale“ Klassen . Du brauchst doch keine Kopien der Zeichnung, oder? Es besteht also keine Notwendigkeit, Instanzen einer abstrakten Klasse zu erstellen :) Und wenn die Klasse
Car
nicht abstrakt wäre, könnten wir ihre Objekte einfach erstellen:
public class Car {
private String model;
private String color;
private int maxSpeed;
public void gas() {
}
public void brake() {
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car();
}
}
Jetzt haben wir irgendein unverständliches Auto in unserem Programm – keinen Lastwagen, keinen Rennwagen, keine Limousine, sondern irgendetwas im Allgemeinen. Dasselbe „nur eine Maschine“, die es in der Natur nicht gibt. Das gleiche Beispiel lässt sich auch bei Tieren anführen. Stellen Sie sich vor, in Ihrem Programm würden Objekte auftauchen
Animal
– „
nur ein Tier “. Um welche Art es sich handelt, zu welcher Familie es gehört und welche Eigenschaften es aufweist, ist unklar. Es wäre seltsam, ihn im Programm zu sehen. In der Natur gibt es keine „gerechten Tiere“. Nur Hunde, Katzen, Füchse, Maulwürfe und andere. Abstrakte Klassen befreien uns von „
nur Objekten “. Sie geben uns einen Grundzustand und ein Verhalten. Beispielsweise müssen alle Autos
ein Modell ,
eine Farbe und
eine Höchstgeschwindigkeit haben , außerdem müssen sie
Gas und
Bremsen können . Das ist alles. Dies ist ein allgemeines abstraktes Schema. Anschließend entwerfen Sie selbst die Klassen, die Sie benötigen.
Bitte beachten Sie: Zwei Methoden in einer abstrakten Klasse werden ebenfalls als
abstract bezeichnet und sind überhaupt nicht implementiert. Der Grund ist derselbe: Abstrakte Klassen erzeugen kein „Standardverhalten“ für „bloße Maschinen“. Sie sagen nur, dass sie in der Lage sein sollten, alle Autos herzustellen. Wenn Sie jedoch weiterhin das Standardverhalten benötigen, können Sie Methoden in einer abstrakten Klasse implementieren. Java verbietet dies nicht:
public abstract class Car {
private String model;
private String color;
private int maxSpeed;
public void gas() {
System.out.println("Lass uns gehen!");
}
public abstract void brake();
}
public class Sedan extends Car {
@Override
public void brake() {
System.out.println(„Die Limousine wird langsamer!“);
}
}
public class Main {
public static void main(String[] args) {
Sedan sedan = new Sedan();
sedan.gas();
}
}
Konsolenausgabe:
„Beschleunigen!“ Wie Sie sehen, haben wir eine Methode in der abstrakten Klasse implementiert, die zweite jedoch nicht. Infolgedessen
Sedan
wurde das Verhalten unserer Klasse in zwei Teile geteilt: Wenn Sie eine Methode darauf aufrufen
gas()
, wird sie von der übergeordneten abstrakten Klasse „abgerufen“
Car
und
brake()
wir haben die Methode in der Klasse neu definiert
Sedan
. Es erwies sich als sehr praktisch und flexibel. Aber jetzt
ist unsere Klasse nicht mehr so abstrakt ? Immerhin wird tatsächlich die Hälfte seiner Methoden umgesetzt. Tatsächlich – und das ist ein sehr wichtiges Merkmal –
ist eine Klasse dann abstrakt, wenn mindestens eine ihrer Methoden abstrakt ist . Mindestens eine von zwei, mindestens eine von tausend Methoden – das spielt keine Rolle. Wir können sogar alle Methoden implementieren und keine abstrakten übrig lassen. Es wird eine abstrakte Klasse ohne abstrakte Methoden geben. Im Prinzip ist dies möglich und der Compiler wird keine Fehler erzeugen, aber es ist besser, dies nicht zu tun: Das Wort „abstrakt“ verliert seine Bedeutung und Ihre Programmierkollegen werden sehr überrascht sein, dies zu sehen :/ Außerdem, wenn eine
Methode mit dem Wort „abstrakt“ gekennzeichnet ist, muss jede abgeleitete Klasse „abstrakt“ implementieren oder als abstrakt deklariert werden. Andernfalls gibt der Compiler einen Fehler aus . Natürlich kann jede Klasse nur von einer abstrakten Klasse erben, sodass es hinsichtlich der Vererbung keinen Unterschied zwischen abstrakten und regulären Klassen gibt. Es spielt keine Rolle, ob wir von einer abstrakten oder einer regulären Klasse erben, es kann nur eine übergeordnete Klasse geben.
Warum gibt es in Java keine Mehrfachklassenvererbung?
Wir haben bereits gesagt, dass es in Java keine Mehrfachvererbung gibt, aber wir haben noch nicht wirklich herausgefunden, warum. Versuchen wir es jetzt. Der Punkt ist, dass untergeordnete Klassen nicht entscheiden könnten, welches Verhalten sie wählen würden, wenn Java über Mehrfachvererbung verfügen würde. Nehmen wir an, wir haben zwei Klassen –
Toster
und
NuclearBomb
:
public class Toster {
public void on() {
System.out.println(„Der Toaster ist an, der Toast wird fertig!“);
}
public void off() {
System.out.println(„Der Toaster ist aus!“);
}
}
public class NuclearBomb {
public void on() {
System.out.println("Взрыв!");
}
}
Wie Sie sehen, haben beide eine Methode
on()
. Im Falle eines Toasters beginnt er, Toast zu backen, und im Falle einer Atombombe löst er eine Explosion aus. Oh :/ Stellen Sie sich nun vor, Sie hätten (ich weiß nicht warum plötzlich!) beschlossen, etwas dazwischen zu schaffen. Und hier ist es deine Klasse -
MysteriousDevice
! Dieser Code funktioniert natürlich nicht und wir präsentieren ihn lediglich als Beispiel dafür, „wie es sein könnte“:
public class MysteriousDevice extends Toster, NuclearBomb {
public static void main(String[] args) {
MysteriousDevice mysteriousDevice = new MysteriousDevice();
mysteriousDevice.on();
}
}
Mal sehen, was wir haben. Das mysteriöse Gerät stammt sowohl vom Toaster als auch von der Atombombe. Beide haben eine Methode
on()
, und daher ist nicht klar, welche Methode
on()
auf das Objekt ausgelöst werden soll,
MysteriousDevice
wenn wir es aufrufen. Das Objekt wird dies nicht verstehen können. Nun, als Kirsche auf dem Kuchen: Die Atombombe hat keine Methode
off()
. Wenn wir also falsch geraten haben, gibt es keine Möglichkeit, das Gerät auszuschalten.
Gerade wegen dieser Verwirrung haben die Entwickler von Java die Mehrfachvererbung aufgegeben, wenn einem Objekt nicht klar ist, welches Verhalten es wählen soll. Sie erinnern sich jedoch daran, dass Java-Klassen viele Schnittstellen implementieren. Übrigens haben Sie in Ihrem Studium schon mindestens eine Abstract-Klasse kennengelernt! Obwohl, vielleicht habe ich es nicht bemerkt :)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
Das ist die Klasse deiner alten Freunde
Calendar
. Es ist abstrakt und hat mehrere Erben. Einer von ihnen ist
GregorianCalendar
. Sie haben es bereits im Unterricht über Datumsangaben verwendet :) Alles scheint klar zu sein, es bleibt nur noch ein Punkt: Was ist der grundlegende
Unterschied zwischen abstrakten Klassen und Schnittstellen ? Warum haben sie beide zu Java hinzugefügt und sich nicht auf nur eines beschränkt? Das könnte durchaus ausreichen. Darüber sprechen wir im nächsten Vortrag! Auf Wiedersehen:)
GO TO FULL VERSION