Einführung in die Grundlagen der objektorientierten Programmierung in Java

In den 1990er Jahren wurden viele objektorientierte Programmiersprachen mit dem Ziel entwickelt, die Programmierung von komplexen Anwendungen einfacher zu gestalten. Die Anwendungen sollten durch objektorientierte Programmierung (OOP) robuster, einfacher zu warten und weniger fehleranfällig werden.

Objektorientierte Programmierung ermöglicht eine natürliche Modellierung, erhöht die Effizienz des Entwicklers durch Wiederverwendbarkeit der Programmelemente und vermindert die Komplexität der Anwendungen durch Abstraktion und Kapselung.

In diesem Beitrag widmen wir uns den Grundlagen der objektorientierten Programmierung und stellen die wichtigsten Konzepte vor.

Die fünf Konzepte der objektorientierten Programmierung in Java sind:

1: Abstraktion – Unterscheidung zwischen Objekten und Klassen in Java

Ein großes Problem bei der Entwicklung von heutigen Anwendungen ist deren Komplexität. Um die Software-Entwicklung aber beherrschbar zu machen, muss diese Komplexität verringert werden.

Und genau dabei hilft Abstraktion. Durch Abstraktion wird zwischen Konzept und Umsetzung unterschieden, d.h. es gibt ein Objekt und einen Bauplan nach dem dieses Objekt modelliert wird.

Android Apps Programmieren Online-Kurs

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Dies hat den Vorteil, dass mit nur einem Bauplan viele sich stark ähnelnde Objekte erzeugt werden können. Ein Objekt ist dabei ein in der Anwendungswelt existierendes „Ding“. Den Bauplan nach dem diese Dinge modelliert werden, bezeichnet man als Klasse.

Es ist immer dann sinnvoll eine Klasse (Bauplan) zu erstellen, wenn mehrere sich ähnelnde Objekte benötigt werden, die nicht exakt gleich sind, aber in vielen Merkmalen miteinander übereinstimmen.

Jede Klasse muss mindestens diese vier Merkmale beschreiben:

  1. Welche Eigenschaften besitzt das Objekt?
  2. Wie verhält sich das Objekt?
  3. Wie wird das Objekt erzeugt?
  4. Wie wird das Objekt bedient?

Eine Klasse könnte beispielsweise den Bauplan von Feuerlöschern beschreiben und exakt vorgeben welche Eigenschaften Feuerlöscher-Objekte besitzen (Farbe, Größe, Inhalt), wie sich Feuerlöscher-Objekte verhalten (was passiert wenn Schalter A gedrückt wird), wie Feuerlöscher-Objekte erzeugt werden (was sind die Start-Bedingungen) und wie Feuerlöscher-Objekte bedient werden (welche Schalter können gedrückt werden und wann).


Ist eine solche Klasse erstellt, können beliebig viele Instanzen dieser Klasse (Objekte) erzeugt werden. Diese Objekte besitzen viele Gemeinsamkeiten, unterscheiden sich aber in einigen Details (Farbe, Größe, …) und jede Instanz besitzt eine eigene Identität.

2: Kapselung – Methoden und Variablen formen zusammen eine Klasse

Eine Klasse besteht aus Variablen und Methoden.

Wird eine Instanz einer Klasse erzeugt, dann enthalten die Variablen die Informationen über den Zustand der Instanz (des Objekts). Diese Variablen werden Instanzvariablen oder auch Attribute, Membervariablen oder Instanzmerkmale genannt.

Jede Instanz einer Klasse verfügt über einen eigenen Satz von Instanzvariablen, diese können mit unterschiedlichen Werten gefüllt sein und verändern sich während der Lebenszeit des Objekts.

Die Methoden einer Klasse bestimmen das Verhalten der Instanzen. Mithilfe der Methoden können die Inhalte der Variablen ausgelesen und verändert werden. Somit ermöglichen die Methoden das Abfragen des Zustands der Instanz und sogar das Verändern des Zustands.

Die Methoden existieren im ausführbaren Programmcode nur einmal. Sie arbeiten bei jedem Aufruf aber mit den Daten einer ganz bestimmten Instanz. Welche Instanz das ist, wird zur Laufzeit beim Methodenaufruf als Verweis übergeben. Die Methode greift dann nur auf die Instanzvariablen dieses einen Objekts zu.

Kapselung ist der Umstand, dass Klassen aus Variablen und Methoden bestehen.

Durch diese Kapselung wird die Komplexität der Bedienung eines Objektes stark reduziert. Um ein Objekt zu bedienen, muss man nicht den inneren Aufbau kennen, sondern nur die entsprechende Methode.

3: Wiederverwendbarkeit – Programmelemente mehrfach nutzen

Ein weiteres sehr wichtiges Konzept der objektorientierten Programmierung ist die Möglichkeit Programmelemente wiederverwenden zu können.

Die Wiederverwendbarkeit wird durch die beiden bereits vorgestellten Konzepte Abstraktion und Kapselung gefördert. Dadurch können Objekte sehr einfach wiederverwendet werden. Der Entwickler muss nur die Schnittstellen kennen und kann damit die Objekte bedienen. Um die komplexen Details der Code- und Datenstrukturen muss sich der Entwickler nicht kümmern.

Ein sehr bekanntes Beispiel für Wiederverwendbarkeit ist die Collection-Klasse, durch die es sehr einfach möglich ist Objekte in einer Sammlung zu verwalten.

Obwohl die Collection-Klasse sehr komplex aufgebaut ist, kann sie dennoch sehr komfortabel über ihre einfache Schnittstelle benutzt werden.

Durch Wiederverwendbarkeit wird die Java-Programmierung effizienter und die Anzahl an Programmierfehlern deutlich reduziert.

4: Beziehungen – Objekte und Klassen stehen in Beziehungen zueinander

In Java gibt es 3 Grundtypen von Beziehungen, die Objekte und Klassen miteinander bilden.

Diese sind:

  1. Generalisierung und Spezialisierung („is-a“ Beziehung)
  2. Aggregation und Komposition („part-of“ Beziehung)
  3. Verwendungsbeziehungen (Assoziationen)

1. Generalisierung und Spezialisierung: Die „is-a“ Beziehung

Die „is-a“ Beziehung tritt zwischen zwei Klassen auf, die zueinander in einer Vererbungsbeziehung stehen.

Die Basisklasse (Vaterklasse) vererbt ihre Merkmale an die von ihr abgeleitete Klasse. Die abgeleitete Klasse wird dabei nicht komplett neu definiert, sondern erbt alle Eigenschaften der Basisklasse und ihr werden neue zusätzliche Eigenschaften hinzugefügt.

Dabei sagt man, dass Klasse B ein A ist (B „is-a“ A) und somit eine Spezialisierung von der Klasse A. Umgekehrt gilt, dass die Basisklasse A eine Generalisierung (Verallgemeinerung) von der abgeleiteten Klasse B ist.

Da Vererbungen mehrstufig sein können, ist es möglich, dass eine abgeleitete Klasse selbst als Basisklasse für weitere Klassen dient. Aufgrund der Mehrstufigkeit bildet sich eine Vererbungshierarchie aus, die als Baumstruktur dargestellt werden kann. Diese Ableitungsbäume werden als Graphen dargestellt.

Die Basisklassen stehen dabei oberhalb der abgeleiteten Klassen. Die Klassen werden mit Pfeilen verbunden, wobei die Pfeilrichtung von der abgeleiteten Klasse in Richtung der Basisklasse verläuft.

Baumstruktur der Vererbungshierarchie in Java (Ableitungsbaum)

Baumstruktur der Vererbungshierarchie in Java am Beispiel von Lebewesen

Die Klasse Lebewesen ist die Basisklasse aller anderen Klassen, d.h. alle Klassen erben ihre Eigenschaften. Die Lebewesen-Klasse besitzt genau eine Eigenschaft, in der das Alter eines Lebewesens gespeichert wird.

Die Klasse Säugetier ist von der Lebewesen-Klasse abgeleitet, somit eine Spezialisierung dieser. Sie erbt das Merkmal Alter und fügt die Eigenschaft AnzahlBeine hinzu.

Die Klassen Mensch und Schaf sind von der Säugetier-Klasse abgeleitet. Beide erben die Merkmale Alter und AnzahlBeine, besitzen jedoch eigene individuelle zusätzliche Eigenschaften.

2. Aggregation und Komposition: Die „part-of“ Beziehung

Die „part-of“ Beziehung beschreibt, woraus sich ein Objekt zusammensetzt.

Ein Objekt kann andere Objekte aufnehmen. Die aufgenommenen Objekte können als die Einzelteile des Hauptobjekts angesehen werden.

Wenn ein Objekt Teil eines anderen Objekts ist, steht es in einer „part-of“ Beziehung mit dem Hauptobjekt. So besitzt ein Mensch bspw. zwei Beine, die Beine sind in diesem Fall Teil („part-of“) des Menschen.

Wenn die aufgenommenen Objekte für das Hauptobjekt existenziell sind, nennt man dies eine Komposition. Sind die aufgenommenen Objekte lediglich optional, dann spricht man von einer Aggregation.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Die Komposition ist die strenge Form der Aggregation, da eine existenzielle Abhängigkeit besteht.

Umgesetzt werden „part-of“ Beziehungen in Java durch Instanzvariablen, die Objekte aufnehmen können. Ist bei einer Aggregation das Objekt nicht vorhanden, wird der entsprechenden Instanzvariable das null-Objekt zugewiesen.

Wird ein Objekt aufgenommen, dann verwendet man dafür eine Instanzvariable. Werden mehrere Objekte des gleichen Datentyps aufgenommen, dann verwendet man eine Array-Instanzvariable vom benötigten Datentyp.

3. Verwendungsbeziehungen: Assoziationen in Java

In Java geben Verwendungsbeziehungen an, dass ein Objekt eine Instanz einer bestimmten Klasse temporär nutzt, um eine bestimmte Operation auszuführen.

Verwendungsbeziehungen treten immer dann auf, wenn Objekte (Instanzen von Klassen) nur temporär verwendet werden. Dies ist bei lokalen Objekt-Variablen und Methodenargumenten der Fall. Solche Objekte existieren nur innerhalb einer Methode, also temporär.

Diese Art von Beziehungen bezeichnet man auch als Assoziationen.

5: Polymorphismus – Objektvariablen können Instanzen abgeleiteter Klassen aufnehmen

In Java ist es möglich, dass eine Objektvariable Objekte aufnehmen kann, die von einem anderen Datentyp sind.

Dieses Konzept nennt man Polymorphismus (Vielgestaltigkeit).

Die Objektvariable ist dabei vom Datentyp der Basisklasse A. Sie kann nicht jedes beliebige Objekt aufnehmen, sondern nur Objekte, die Instanzen einer von der Basisklasse A abgeleiteten Klasse sind.

Im konkreten Fall bedeutet dies, dass eine Objektvariable vom Typ Lebewesen sowohl Objekte vom Typ Lebewesen (Instanzen der Klasse Lebewesen) als auch Objekte vom Typ Säugetier, Mensch, Schaf, Vogel, Fisch, Hecht und Karpfen (Instanzen der von der Basisklasse Lebewesen abgeleiteten Klassen) aufnehmen kann.

Die Flexibilität wird durch den Java-Compiler ermöglicht, indem dieser sicherstellt, dass nur auf die Eigenschaften der Klasse der Objektvariable zugegriffen werden kann. Denn diese Eigenschaften sind aufgrund der Vererbungshierarchie in jedem zuweisbaren Objekt mindestens vorhanden.

Lebewesen allgemeinesLW; // Objektvariable vom Typ der Basisklasse Lebewesen

// Objektvariable vom Typ Lebewesen bekommt Instanz der Klasse Lebewesen zugewiesen
allgemeinesLW = new Lebewesen(); // erlaubt, der Standardfall

Mensch menschLW = new Mensch();
Schaf schafLW   = new Schaf();

// Objektvariable vom Typ Lebewesen bekommt Instanz der Klasse Mensch zugewiesen
allgemeinesLW = menschLW; // Polymorphismus - erlaubt, wegen Spezialisierung

// Objektvariable vom Typ Lebewesen bekommt Instanz der Klasse Schaf zugewiesen
allgemeinesLW = schafLW; // Polymorphismus - erlaubt, wegen Spezialisierung

// Objektvariable vom Typ Schaf bekommt Instanz der Klasse Lebewesen zugewiesen
schafLW  = allgemeinesLW; // nicht erlaubt, wegen Generalisierung

// Objektvariable vom Typ Schaf bekommt Instanz der Klasse Mensch zugewiesen
schafLW  = menschLW; // nicht erlaubt, da gleiche Hierarchieebene 

Polymorphismus ist nur von der allgemeinen Klasse (Hauptklasse) in Richtung der spezialisierten Klasse (abgeleiteten Klasse) erlaubt.

Eine Objektvariable vom Typ der abgeleiteten Klasse kann kein Objekt der Basisklasse aufnehmen, da das Basisklassen-Objekt nicht alle Eigenschaften der abgeleiteten Klasse besitzt. Auf diese Eigenschaften könnte aber über die Objektvariable zugegriffen werden, was zu undefiniertem Programmverhalten führen würde.

Das Konzept des Polymorphismus ermöglicht das sogenannte Late Binding, wodurch Methoden überlagert werden können. Dabei wird eine Methode bereits in der Basisklasse implementiert, aber in den abgeleiteten Klassen von einer spezielleren Methoden-Implementierung überlagert. Zur Laufzeit wird dann entschieden welche Methoden-Implementierung ausgeführt wird.

So könnte beispielsweise die Klasse Lebewesen eine Methode getFortbewegungsart besitzen. Diese Methode liefert die Fortbewegungsart des Lebewesen-Objekts zurück. Jede abgeleitete Klasse könnte eine eigene Version der Methode getFortbewegungsart implementieren, welche dann zur Laufzeit des Programms anstelle der allgemeinen Methode getFortbewegungsart der Basisklasse ausgeführt werden würde.

Falls eine Methode in der abgeleiteten Klasse nicht erneut implementiert wurde, es also keine Überlagerung gibt, wird vom Laufzeitsystem einfach die Methoden-Implementierung aus der Vaterklasse verwendet, die der eigenen Klasse am nächsten liegt.


Comments 3

  1. Pingback: Klassen in Java: Abstraktion zwischen Klassen und Objekten (Instanzen von Klassen) -

  2. Pingback: Java-Grundlagen: Vererbung - Ableiten einer Klasse in Java

  3. Pingback: Klassen und Objekte (Instanzen von Klassen) in Java

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.