java.sun.com

   JAVA - Eine objektorientierte Programmiersprache


 Startseite
 Grundlagen

 Indexverzeichnis


JAVA - Eine objektorientierte Programmiersprache

Java ist eine objektorientierte Programmiersprache - das bedeutet, dass beim Programmieren Objekte verwendet werden, die den Ablauf des Programmes bestimmen. In diesem Abschnitt möchte ich den Begriff Objektorientierung allgemein erklären und die Bedeutung und Auswirkungen auf das Programmieren erfassen.

Seit ca. fünf Jahren gibt es effiziente Werkzeuge zum Entwerfen von komplexen Programmen. Dabei werden die Objekte und ihr Zusammenhang innerhalb eines Systems grafisch dargestellt, nicht aber die Programmierung. Leider haben diese Werkzeuge unterschiedliche Darstellungen verwendet. Seit ca. zwei Jahren scheint es gelungen zu sein, die Darstellung weltweit zu vereinheitlichen und in Form der UML (Unified Modelling Language) herauszubringen.

Seitdem hat die Modellierung eines Problemes nicht nur die Programmierabteilungen erfasst, sondern ist in völlig andere Bereiche eingedrungen (auch Anwender und Geschäftsleitung reden jetzt bei Problemen mit). Mit Hilfe der UML ist es gelungen, dass sich alle beteiligten Stellen einer einheitlichen Sprache bedienen (vom Management bis zur Buchhaltung) und Probleme bei der Umsetzung in ein Programm verstehen können.

Genau deshalb glaube ich, das UML als Verständigungsmittel zwischen Gruppen, Abteilungen und Management in Zukunft immer öfters eingesetzt wird (weiss ich aus eigener Erfahrung!). Ich selbst kenne einige Firmen in der UML als Voraussetzung für einen Job absolut notwendig ist, unabhängig von der Position.

Ich habe deshalb versucht bei der Objektorientierung die Grundlagen von UML soweit es Objekte betrifft mitzunehmen.

Was sind Objekte?
Was sind Klassen?
Was ist Vererbung?
Was ist Polymorphismus?
Was ist Kapselung?

Objekte und ihr Lebenszyklus
Was sind Instanzvariablen?
Was sind Klassenvariablen?

  Seitenende


Was sind Objekte?

Sehen wir uns zuerst einige Objekte an, die uns tagtäglich über den Weg laufen:
Ein Auto mit einem bestimmten Kennzeichen, das zusammengefallene Haus an der Ecke, der Computer am Arbeitsplatz, die Eiche im Park, die Homepage eines Freundes, die Person, die mir immer den letzten Parkplatz wegschnappt, usw.

All das sind Objekte, wie wir sie ebenfalls beim Programmieren kennen oder noch kennenlernen werden. Wir verwenden ein Objekt im Programm als Abbild der realen Welt. Jeder von uns hat schon einmal in ein Adressenverzeichnis eine Person eingegeben. Jede Person in dem Adressverzeichnis entspricht also einem Objekt.

Was verbindet nun diese höchst unterschiedlichen Objekte miteinander, damit wir sie als Regelwerk in einem Programm verwenden können?
Jedes dieser Objekte besitzt Eigenschaften, die wir beschreiben können.
Das Auto besitzt ein Kennzeichen, eine Farbe, eine Geschwindigkeit, eine Länge, usw.
Das Haus hat Mauern, Fenster, Türen, eine Grundfarbe, ein Dach, usw.
Der Computer besitzt eine Taktfrequenz, Speicherplatz, ein CD-Laufwerk, usw.
Die Eiche hat einen Stamm, Blätter, Zweige, Äste, usw.
Die Homepage besitzt eine Adresse, Inhalt (hoffentlich), Links, Grafiken, usw.
Die Person besitzt einen Namen, Haar- und Augenfarbe, Grösse, Geschlecht, usw.

Alle die genannten Eigenschaften können einem Objekt als Eigenschaften zugeordnet werden. Und ein Objekt besitzt noch etwas sehr wichtiges. Nämlich die Möglichkeit aktiv zu sein (etwas zu tun und etwas zu veranlassen).

Sehen wir uns einige Möglichkeiten unserer Beispielobjekte an:
Das Auto kann sich bewegen, blinken, bschleunigen, bremsen, usw.
Das Haus kann Fenster und Türen öffen/schliessen und auch zusammenfallen.
Der Computer kann rechnen, lesen, speichern, abstürzen, usw.
Die Eiche kann wachsen, grünen, Früchte tragen, usw.
Die Homepage kann auf andere Seiten weiterleiten, Grafik animieren, Musik abspielen, usw.
Und was die Person alles kann, muss ich nicht extra erwähnen.

Die verschiedenen Möglichkeiten eines Objektes aktiv zu sein, bezeichnet man beim Programmieren als Methoden des Objektes.

Kurz zusammengefasst:
Ein Objekt besteht aus Eigenschaften und Methoden und ist ein Teil unserer realen Welt. Die Eigenschaften und Methoden eines Objektes bestimmen dessen Verhalten.

Wenn wir von Eigenschaften eines Objektes sprechen, so meinen wir den Namen der Eigenschaft und nicht die Ausführung (Ausprägung). Das heisst, selbst wenn sie die gleichen Eigenschaften und Methoden besitzen, unterscheiden sie sich immer noch durch die Ausprägung der Eigenschaften.
Zwei Autos vom gleichen Typ unterscheiden sich durch die Farben rot und blau und natürlich durch die Nummer des Kennzeichens.

Wir unterscheiden also gleiche Objekte voneinander, indem wir ihre Eigenschaften ansehen und miteinander vergleichen.

  Seitenanfang


Was sind Klassen?

Wenn wir den Typ eines Objektes beschreiben, so definieren wir die Eigenschaften (ohne Ausprägung) und die Methoden. Auf diese Weise erhalten wir eine Definition, die für jedes Objekt dieses Typs gilt.

Versuchen wir ein Auto ganz einfach zu definieren:
Eigenschaften:
- Farbe
- Geschwindigkeit

Methoden:
- beschleunigen
- bremsen

UML-Darstellung

Die Beschreibung ist zwar nicht vollständig, erklärt aber das Wesentliche.

In unserer Definition betrachten wir das Objekt sehr, sehr abstrakt. Wir definieren dabei keine Ausprägung (wie z.B. rot oder blau), sondern nur die Eigenschaft Farbe. Dadurch passt die Definition für mehrere verschiedene Objekte. In unserem Beispiel ist es völlig egal welche Farbe und welche Geschwindigkeit ein Auto im Moment hat. Unsere Beschreibung passt für sowohl für mein bzw. dein Auto, wie auch für das Auto des Nachbarn. Die Bedeutung der Symbole im UML-Diagramm hängt vom verwendeten Werkzeug ab und ist nicht einheitlich geregelt. In unserem Fall werden damit Eigenschaften und Methoden unterschieden.

Solch eine abstrakte Definition eines Objektes wird beim Programmieren als Klasse (class) bezeichnet. Eine Klasse ist also eine abstrakte Beschreibung von einer Gruppe von Objekten aus der realen Welt, die gleiche Eigenschaften und Methoden besitzen.

Eine ähnliche abstrakte Definition können wir auch mit den anderen Objekten anstellen, sei es ein Haus, ein Computer, ein Baum, eine Homepage, eine Person, oder irgend etwas anderes.

  Seitenanfang


Was ist Vererbung?

Beim Erstellen von Klassen, bestimmen wir das Verhalten von Objekten. In vielen Fällen entdecken wir Ähnlichkeiten zwischen den verschiedenen Klassen, obwohl das Verhalten der Objekte sehr unterschiedlich ist.

Ein Lastwagen verhält sich in der realen Welt anders als ein Sportwagen. Während beim Sportwagen die Beschleunigung als Eigenschaft sehr wichtig ist, spielt sie beim Lastwagen keine Rolle. Umgekehrt ist das max. erlaubte Gewicht beim Sportwagen belanglos, aber beim Lastwagen sehr wichtig. Beim Autobus ist jede dieser Eigenschaften wichtig.

Gibt es eine Möglichkeit dieses unterschiedliche Verhalten zu vereinen? Denn genau genommen besitzen alle diese unterschiedlichen Objekte gemeinsame Eigenschaften, auch wenn sie von Objekt zu Objekt variieren. Versuchen wir die Gemeinsamkeiten zu finden und sie in einer eigenen Klasse zu definieren.

Sowohl der Sportwagen, als auch der Lastwagen bzw. der Autobus besitzen gleiche Eigenschaften, wie Länge, Breite, Höhe, Anzahl der Räder, Anzahl der Sitzplätze, usw. Diese Gemeinsamkeiten definieren wir in einer Klasse Auto:
class Auto
 Eigenschaften:
 - Länge
 - Breite
 - Höhe
 - Radanzahl
 - Sitzplatzanzahl
  
 Methoden:
 - beschleunigen
 - bremsen

UML-Darstellung

Sehen wir uns jetzt an, was die Klassen voneinander unterscheidet:
Der Lastwagen besitzt eine zusätzliche Eigenschaft max. Gewicht, der Sportwagen die Eigenschaft Beschleunigung und der städtische Autobus die Eigenschaft Anzahl der Stehplätze. Dazu benötigen die Klassen noch jeweils eigene Methoden um das spezielle Verhalten zu steuern.

Bei der Definition dieser speziellen Klassen beziehen wir uns auf die bereits definierte Klasse Auto. Dadurch können wir die Methoden der Klasse Auto weiterverwenden und ersparen uns dadurch eine Menge Arbeit. Der Mechanismus, den wir dazu einsetzen, heisst Vererbung (Inheritance).
class Sportwagen erbt von Auto
 Eigenschaften:
 - Beschleunigung
 
 Methoden:
 keine 
Lastwagen erbt von Auto
 Eigenschaften:
 -  max. Zuladung
 
 Methoden:
 - zuladen
 - entladen 
Autobus erbt von Auto
 Eigenschaften:
 - Stehplatzanzahl
 
 Methoden:
 - einsteigen
 - aussteigen

Wenn wir den Ausdruck erbt von verwenden, dann übernehmen wir alle Eigenschaften und Methoden einer Klasse in unsere neue Klasse. Die Klasse Sportwagen kann die Methoden beschleunigen und bremsen der übergeordneten Klasse Auto genauso verwenden, wie der Lastwagen oder der Autobus. Für uns bedeutet das beim Programmieren, dass wir diese Methoden nicht neu machen müssen, sondern uns darauf verlassen können dass sie funktionieren. Der Vererbungsmechanismus in der Programmiersprache sorgt dafür, dass wir die Methode bremsen der Klasse Sportwagen ausführen können, obwohl sie in der Klasse Auto definiert ist.

In der nebenstehende Abbildung wird gezeigt, wie Vererbung in einem UML-Diagramm dargestellt wird. Die Pfeile zeigen in die Richtung zur übergeordneten Klasse und bedeuten erbt von.

Beim Programmieren nennen wir die übergeordnete Klasse (von der vererbt wird) Basisklasse oder Superclass, die neue, vererbte Klasse nennen wir Derivat oder Subclass. Das Derivat kann Methoden und Eigenschaften der Basisklasse verwenden, als seien es seine eigenen.

Ist bereits eine Sammlung von Klassen vorhanden, so können wir sie verwenden, um eigene Klassen davon abzuleiten und Programme zu erstellen. In dem Java JDK sind bereits sehr viele Klassen, für alle möglichen Objekte, vorhanden. Benötigen wir für ein Objekt eine neue Klasse, so suchen wir uns die Klasse, die die Anforderungen am besten erfüllt, aus dem JDK heraus und verwenden sie als Basisklasse. Die neue Klasse erweitern wir um die noch fehlenden Eigenschaften und Methoden. Mit dem Vererbungsmechanismus sind wir in der Lage Klassen wiederzuverwenden, ohne sie neu zu definieren. Dabei spielt es keine Rolle von wem die Klassen definiert wurde.

Manche objektorientierten Programmiersprachen sind in der Lage eine Vererbung von mehreren Basisklassen zu einer neuen Klasse herbeizuführen. Dabei werden alle Eigenschaften und alle Methoden sämtlicher Basisklassen auf die abgeleitete Klasse vererbt. Diese Funktionalität hat die Programmierer dieser Welt in zwei Lager gespalten. Die eine Seite behauptet, zum objektorientierten Programmieren gehört die Mehrfachvererbung unbedingt dazu, die andere Seite kontert damit, dass die Mehrfachvererbung ein Programm nur unübersichtlich und unverständlich macht. Tatsache ist, dass es immer noch keinen einzigen Fall der Mehrfachvererbung gibt, der sich nicht durch normale Vererbung ersetzen lassen würde.

In der Programmiersprache Java ist eine Mehrfachvererbung nicht erlaubt. Diese Möglichkeit wird aber durch das mehrfache implementieren von Interfaces (Schnittstellen) erreicht. Dazu gibt es später mehr Information.

  Seitenanfang


Was ist Polymorphismus?

Wenn wir das obige Beispiel mit dem Auto und den Sportwagen genauer betrachten, dann entsteht ein Problem. Die Klasse Sportwagen besitzt keine eigene Methode beschleunigen, denn sie verwendet die Methode aus der Basisklasse Auto. Wir wollen jetzt einen speziellen Sportwagen, ein Raketenauto, entwerfen, das die gleichen Eigenschaften wie der Sportwagen besitzt. Nur die Methode beschleunigen funktioniert gänzlich anders, als die des Sportwagens.

Wir definieren also ein Raketenauto, dass wir vom Sportwagen ableiten:
class Raketenauto erbt von Sportwagen
 Eigenschaften:
 keine
 
 Methoden:
 - beschleunigen

Wie wir hier sehen, gibt es plötzlich zwei Methoden beschleunigen, die vollkommen verschieden sein können. Einmal direkt bei der Klasse Raketenauto und einmal in der Basisklasse Auto, von der ja die Klasse Sportwagen abgeleitet wurde. Eine objektorientierte Programmiersprache wird in diesem Fall immer die Methode, die der Klasse direkt zugeordnet ist, aufrufen. Dieses Verhalten bezeichnet man als Polymorphismus. In der Klassenhierarchie kann es mehrere verschiedene Methoden mit gleichen Namen geben. Je nachdem welche Klasse einem Objekt zugeordnet ist, verhält sich das Objekt anders, es ist polymorph.

  Seitenanfang


Was ist Kapselung?

Bis hierher haben wir noch keine besondere Funktionalität angesprochen, die nicht auch mit herkömmlichen, prozeduralen Programmiersprachen (mehr oder minder schwierig) erreicht werden könnte. Es ging bis jetzt auch nur um die Denkweise oder anders gesagt, um eine andere Sichtweise für ein bestimmtes Problem.

Mit Hilfe der Kapselung sind wir in der Lage, Eigenschaften und Methoden einer Klasse vor der Aussenwelt zu verstecken. Für Programmierer bedeutet das, dass sie nicht mehr in der Lage sind zu ermitteln, wie ein Objekt eine bestimmte Aufgabe erledigt. Solange das richtig funktioniert, ist es auch nicht wichtig wie es funktioniert. Wir müssen uns eben darauf verlassen, dass es richtig funktioniert. Aber das ist nur ein Aspekt, ein weiterer Aspekt ist, und der ist wesentlich wichtiger, dass wir Eigenschaften eines Objektes verbergen können. Zu Anfang scheint das ein Nachteil zu sein, aber mit fortgeschrittener Programmierung, wird diese Funktion immer wertvoller und einsetzbarer werden.

Sehen wir uns dazu ein einfaches Beispiel an:
Nehmen wir die Methode beschleunigen unserer Klasse Auto. Die Methode verwendet eine weitere Methode Treibstoff erhöhen und führt davor noch einige Prüfungen aus, wie z.B. Treibstoff vorhanden, Drehzahl ok und Motor nicht zu heiss. Für diese Prüfungen benötigen wir noch einige Eigenschaften, die wir ebenfalls definieren. Diese Eigenschaften verbergen wir von der Aussenwelt. Wir wollen schliesslich nicht, das jemand der keine Ahnung hat, daran manipuliert. Die Methode beschleunigen hingegen stellen wir öffentlich zur Verfügung und jeder der ein Objekt Auto beschleunigen will, kann sie verwenden.
class Auto
Eigenschaften:
 - (geschützt) Treibstoffmenge
 - (geschützt) Drehzahl
 - (geschützt) Motortemperatur
  
 Methoden:
 - (geschützt) Treibstoff erhöhen
 - (öffentlich) beschleunigen
   wenn
     - Drehzahl kleiner 5000 U/min? und
     - Motortemperatur kleiner 90 Grad? und
     - Treibstoffmenge ausreichend?
   dann
     - Treibstoff erhöhen
- (öffentlich) bremsen
UML verwendet Symbole um Eigenschaften und Methoden als geschützt oder öffentlich zu markieren (in unserem Fall einen Schlüssel). Leider sind die Symbole nicht einheitlich.


UML-Darstellung

In diesem Beispiel sehen wir wie die Kapselung arbeitet und welchen Vorteil sie bietet. Wenn jemand die Methode beschleunigen verwendet, werden automatisch die richtigen Prüfungen durchgeführt bevor etwas passiert. Stimmt eines der Eigenschaften nicht, so beschleunigt unser Objekt Auto nicht. Dadurch, dass wir die Eigenschaften vor äusserem Zugriff schützen, verbieten wir, dass sie jemand ohne unser Wissen ändert. Durch das Schützen der Methode Treibstoff erhöhen erreichen wir auch, dass niemand die Prüfungen umgeht, indem er die Methode direkt aufruft.

Diese Vorgehensweise sieht für Programmierer jetzt etwas umständlich oder behindernd aus (schliesslich haben wir Programmierer immer alles im Griff), aber wenn wir wiederverwendbaren Programmcode schreiben wollen, bleibt uns nichts anderes übrig. Denn wer weiss noch wie eine bestimmte Klasse, die vor sechs Monaten entstanden ist, funktioniert und überhaupt von einem Mitarbeiter erstellt wurde, der seit einem Monat ncht mehr bei uns arbeitet.

Das bedeutet aber nicht, das die Softwarekomponenten nicht getestet werden müssen. Denn je besser die Tests stattfinden, desto verlässlicher funktionieren die Objekte. Und ich erwähnte schon: Solange die Klassen funktionieren, ist es nicht wichtig wie sie funktionieren - wir müssen uns darauf verlassen (können).

Beim der Kapselung von Eigenschaften und Methoden gibt es drei Möglichkeiten:
  1. public (öffentlich) - jeder darf die Eigenschaft ändern und die Methoden verwenden
  2. protected (geschützt) - Methoden der eigenen und aller abgeleiteten Klassen dürfen die Eigenschaften ändern und die Methoden verwenden
  3. private (privat) - nur die Methoden der eigenen Klasse dürfen die Eigenschaften ändern und die Methoden verwenden

  Seitenanfang


Objekte und ihr Lebenszyklus

Ein Objekt besitzt immer einen Lebenszyklus, d.h. es muss innerhalb eines Programmes einmal erzeugt werden, ändert dann im Laufe seiner Existenz seinen Zustand und ist aktiv. Wenn es nicht mehr benötigt wird, muss es zerstört werden.
Unser Beispielauto entsteht in den Moment an dem es die Fabrik verlässt, hat dann hoffentlich ein langes Leben und wird beim Verschrotten endgültig zerstört.

Genauso verhalten sich unsere Programmobjekte. Beim Erzeugen eines Objektes wird eine spezielle Methode der Klasse aufgerufen, der sogenannte Konstruktor (Constructor). Diese Methode benutzen wir um dem neuen Objekt Anfangswerte mitzugeben. Alle weiteren Methoden verwenden zum Steuern unseres Programmablaufes. Beim Zerstören des Objektes wird die Destructor-Methode aufgerufen. In einigen Programmiersprachen können wir diese Methode nutzen um Aufräumungsarbeiten durchzuführen, bevor das Objekt endgültig weg ist.

In der Programmiersprache Java gibt es bei Objekten keine Destructor-Methode und um das Zerstören eines Objektes müssen wir uns nicht kümmern. In der Java VM existiert ein Müllsammler (garbage collector), der nicht mehr benötigte Objekte aufsammelt und sie von Zeit zu Zeit zerstört. In einigen Programmiersprachen, wie C++, die keinen Garbage collector besitzen, muss das Programm für die Zerstörung der Objekte Sorge tragen.

  Seitenanfang


Was sind Instanzvariablen?

Eine Klasse verwenden wir, um eine Gruppe von Objekten aus der realen Welt allgemein zu beschreiben. Verschiedene Objekte dieser Klasse erzeugen wir in einem Javaprogramm mit dem Befehl new und weisen den Eigenschaften Werte zu.
auto1 = new Auto
auto1.Farbe = "schwarz"
auto2 = new Auto
auto2.Farbe = "blau"
auto3 = new Auto
auto3.Farbe = "rot"
In diesem Beispiel erzeugen wir aus der Klasse Auto die drei Objekte auto1, auto2 und auto3. Den drei Objekten weisen wir in der Eigenschaft Farbe verschiedene Farben zu. Wann immer wir wollen, können wir der Eigenschaft Farbe andere Werte zuweisen.

Die Objekte auto1, auto2 und auto3 nennt man auch Instanzen (Instance) der Klasse Auto.

Wir sehen aus dem Beispiel, das sich die Eigenschaften der Objekte wie Variablen eines Programmes verhalten. Wir können ihnen Werte zuweisen und sie wieder ändern. Unsere Objekte (nicht die Klassen) besitzen also Eigenschaften, die wie Variablen des Objektes funktionieren. Da man Objekte auch Instanzen nennt, heissen die Variablen, die Werte tragen können, Instanzvariablen. Instanzen besitzen aber auch Methoden, die auf die eigenen Variablen einwirken.

Zusammengefasst: Ein Objekt (Instanz) ist eine Ausprägung einer Klasse. Sie bestehen aus Variablen, die Werte besitzen und Methoden, die diese Variablen verändern können. Wenn wir mit Objekten (Instanzen) arbeiten, sind wir in der Lage, Programmcode und Daten aneinander zu koppeln und sie als ein gemeinsames Element zu betrachten. Und genau diese Funktionalität besitzen herkömmliche Programmiersprachen nicht.

  Seitenanfang


Was sind Klassenvariablen?

Klassenvariable werden auch statische (static) Variablen genannt. Sie sind eine Eigenschaft der Klasse (nicht der Instanz) und besitzen einen Wert. In der Programmiersprache Java gibt es einen eigenen Befehl static, um Klassenvariablen zu definieren. Zum Unterschied von Instanzvariablen (die den Wert innerhalb der Instanz speichern), legen Klassenvariable den Wert in der Klasse ab. Jedes Objekt (Instanz) einer Klasse kann auf die Klassenvariablen zugreifen und sie ändern. Das bedeutet aber auch, da es die Klasse nur einmal gibt, das der Wert einer Klassenvariable für alle Instanzen geändert wird.
// Klasse Auto definieren
public class Auto {
// Eigenschaften:
   static public int Gesamtanzahl;
// Methoden:
   public Auto() { Gesamtzahl++; }
}

// Klasse Auto verwenden
public void main() {
   auto1 = new Auto();
   auto2 = new Auto();
   auto3 = new Auto();
}
In diesem Beispiel verwenden wir zum erstenmal Javasyntax. Es liess sich leider nicht anders erklären.

Zuerst definieren wir in der Klasse Auto die Constructor-Methode Auto(). In dieser Methode erhöhen wir die statische Variable Gesamtanzahl um eins. Das bedeutet, dass jedesmal wenn der Constructor aufgerufen wird, die Klassenvariable Gesamtzahl um eins erhöht wird.

In unserem Programm (hier nur teilweise dargestellt) erzeugen wir mit dem Befehl new drei Instanzen der Klasse Auto. Beim Erzeugen der Instanz wird der Constructor immer automatisch aufgerufen und die Klassenvariable erhöht. Da die Klassenvariable für alle Instanzen nur einmal vorhanden ist, besitzt sie zum Schluss den Wert drei. Wir wissen also, wieviele Instanzen erzeugt wurde.

Methoden einer Klasse können ebenfalls mit static versehen werden. Solche Methoden werden Klassenmethoden genannt. Im Unterschied zu den normalen Methoden, die nur von Instanzen verwendet werden können, brauchen wir bei Klassenmethoden keine Instanz zu erstellen, um sie auszuführen. Deshalb unterliegen sie auch diversen Einschränkungen, wie z.B. dass sie nur Klassenvariable verwenden dürfen und keine Instanzen von Klassen erzeugen können.

 
weiter:
zurück:
  Wie arbeitet man mit Klassen, Methoden usw.
  Grundlagen
  Seitenanfang © 1999-2001  Johann Plank