.: java - einführung in klassen :.
 
abyter.de \\ workshops

< Fortsetzung von letzter Seite

Beispielprojekt: Statische Methoden und Variablen
Theoretisch mag man den Sachverhalt nun verstanden haben, jedoch möchte ich das aus noch praktisch verdeutlichen. Ich möchte einen Umrechner für kW in PS-Beträge entwerfen. Der Benutzer soll eine Zahl eingeben und dann wählen dürfen, ob er von kW in PS oder anders herum konvertieren möchte. Eine statische Methode soll dann prüfen, ob die korrekte Zahl eingegeben wurde. Eine andere Methode soll dann die Berechnung vornehmen, das ganze wird dann schön formatiert ausgegeben. Der Quelltext dazu soll so aussehen:

import java.lang.Math;

public class Rechner
{
private int zahl;
public static int auswahl;
public static void setAuswahl(int w)
{
if (w==1 || w ==2)
auswahl =w;
else auswahl=1;
}

public void setZahl(int zahl)
{
if(zahl >=0) this.zahl=zahl;
else zahl=1;
}
public void showErgebnis()
{
int erg;
if(auswahl==1)
{
erg = (int)Math.floor((zahl * 1.361) + 0.5d);
System.out.println(zahl+"kW entsprechen "+ erg+"PS!"); }
else
{
erg = (int)Math.floor((zahl * 0.735) + 0.5d);
System.out.println(zahl+"PS entsprechen "+ erg+"kW!");
}
}
}

So sieht die Hauptklasse aus:

import java.io.*;

public class Haupt
{
public static void main(String argv[]) throws IOException
{
BufferedReader in = new BufferedReader (new InputStreamReader(System.in));
Rechner r1;
r1 = new Rechner();
System.out.println(" - kW-PS Umrechner -");
System.out.println(" ----------------------------");
System.out.print("Für Umrechnung kW->PS (1), für PS->kW (2) eingeben:");
Rechner.setAuswahl(Integer.parseInt(in.readLine()));
System.out.print("Bitte Betrag eingeben:");
r1.setZahl(Integer.parseInt(in.readLine()));
r1.showErgebnis();
}
}

Konstruktor
Ich möchte noch etwas zum Konstruktor loswerden. Zur Erinnerung: Der Konstruktor ist bei der Erzeugung von Instanzen einer Klasse für die Reservierung von Speicherplatz für die Instanz zuständig.
Bisher haben wir den Konstruktor (z.B. r1 = new Rechner();) immer nur aufgerufen. Mittlerweile sollte jedem klar sein, dass in Java immer alles definiert sein muss, bevor man es ausrufen kann. So ist es - wie sollte es auch anders sein - auch bei den Konstruktoren. Eigentlich braucht man sich in Java nicht um den Konstruktor zu kümmern, da der Compiler (der Übersetzer des Quellcodes in Bytecode) so freundlich ist und - sollte keiner definiert sein - diesen in der Klasse durch den Standardkonstruktor ergänzt.
Es hat jedoch einen Grund, warum ich trotzdem auf den Konstruktor eingehe: Der Standardkonstruktor hat keine Parameter! Manchmal ist es jedoch sinnvoll mit Parametern zu arbeiten. Schließlich kann man diese überladen. Da haben wir es schon! Durch Parameter kann man Überladen und durch Überladen wird das Ganze flexibler und benutzerfreundlicher. Das ist ein sehr guter Grund die wenigen Zeilen der Definition des Konstruktors selber zu übernehmen.
Der Konstruktor ist eine Art "Methode ohne Rückgabewert" und trägt immer denselben Namen wir die Klasse in der er steht. Der Konstruktor hat KEINEN Rückgabewert (aus diesem Grund ist NICHT mit void zu arbeiten!). Bei der Klasse "Rechner" sieht der Konstruktor also so aus:

public Rechner()
{
}

Die Konstruktoren können in der Klassendefinition zwar an einer beliebigen Stelle stehen, jedoch ist es guter Stil folgende Reihenfolge einzuhalten: Attribute, Konstruktoren, Methoden.

Vererbung
Die Vererbung ist eines der wichtigsten objektorientierten Prinzipien der Klassen. Die Vererbung in Java ist im Grunde genommen der des Menschen ganz ähnlich. Der Vorfahr - in Java die Ober- oder Superklasse - vererbt an den Nachfahr - in Java die Unter- oder Subklasse - alle Eigenschaften, jedoch kann der Nachfahr noch einige Eigenschaften zusätzlich haben. In der Praxis sieht das so aus: Es wird eine allgemeine Klasse erstellt, z.B. Mensch, danach wird eine weitere spezifischere Klasse, z.B. Arbeiter, erstellt, bei der wird Vererbung eingesetzt, d.h. alle Eigenschaften werden automatisch übernommen und in der zweiten Klasse werden zu den Eigenschaften die die Klasse schon von der ersten geerbt hat noch weitere spezifische Eigenschaften hinzugefügt. So braucht man die allgemeinen Eigenschaften nur einmal definieren und kann diese in den speziellen Klassen um spezielle Eigenschaften erweitern.
In Java wird die Vererbung mit folgender Syntax vollzogen:

public class Klasse1
{ ... }

public class Klasse2 extends Klasse1
{ ... }

Klasse1 ist die Oberklasse und Klasse2 die Unterklasse. Man sieht, dass die eigentliche Vererbung mit extends Oberklasse von Statten geht. Nun kann man auch auf die geerbten Eigenschaften von Klasse2 zugreifen als wären es die eigenen Eigenschaften. Ist z.B. in Klasse1 das Attribut name vereinbart, so ist es möglich auf dieses Attribut der Klasse2 mittels Klasse2.name zuzugreifen, obwohl doch eigentlich in Klasse2 kein solches Attribut vereinbart wurde; die Vererbung macht's möglich!

Wir haben uns einige Abschnitte zuvor mit Modifiern befasst. Diese haben auch Einfluss auf die Vererbung! Ist ein Attribut oder eine Methode mit private gekennzeichnet, so wird diese NICHT mitvererbt, sondern bleibt gemäß der Definition in der Oberklasse. Zusätzlich zu dem Modifier private kommt bei der Vererbung noch der Modifier protected ins Spiel.
Dieser Modifier bewirkt in der Oberklasse das gleiche wie der Modifier private (der Zugriff von außen wird verhindert), jedoch können Attribute oder Methoden, die mit protected gekennzeichnet sind mitvererbt werden. So haben diese Attribute oder Methoden auch in der Unterklasse die zugriffsbeschränkenden Eigenschaften.

Methoden überschreiben
Bei der Vererbung werden Eigenschaften aus der Oberklasse an die Unterklasse vererbt und um Methoden und Attribute ergänzt. Wenn aber in der Unterklasse eine Methode mit dem gleichen Namen, der gleichen Parameterliste und dem gleichen Rückgabewert definiert wird, so nennt man das Überschreiben einer Methode.
Beim Überschreiben der Methode gibt es zwei Möglichkeiten, entweder man will eine ganz neue Definition der Methode durchführen, oder man will die Methode nur erweitern. Wenn man die Methode nur erweitern will, so kann man mit der Referenz super auf die Eigenschaft der Oberklasse verweisen. Folgendes Beispiel soll das verdeutlichen:

public class Klasse1
{
public void meth()
{
System.out.println("Sehr geehrte Damen,");
}
}
public class Klasse2 extends Klasse1
{
public void meth()
{
super.meth();
System.out.println("liebe Herren");
}
}
public class Haupt
{
public static void main (String argv[])
{
Klasse2 k = new Klasse2();
k.meth();
}
}

Die abgeleitete Klasse sorgt dafür, dass nicht nur 'Sehr geehrte Damen,' sondern auch noch eine Zeile tiefer 'liebe Herren' ausgegeben wird.
Hinter super muss immer eine Methode oder ein Attribut stehen!

Konstruktoren und Vererbung
Konstruktoren werden nicht vererbt. Deswegen muss man bei Bedarf in den Unterklassen ganz neue Konstruktoren definieren. Wenn ein Objekt einer Unterklasse erzeugt wird, ruft der Konstruktor der Unterklasse automatisch den Standard-Konstruktor der Oberklasse auf.
Wie schon soeben beim Überschreiben der Methoden, kommt auch jetzt wieder das Schlüsselwort super zum Einsatz. Diesmal jedoch gelten andere Regel für die Benutzung! Denn nun darf keine Anweisung vor dem Aufruf des Konstruktors stehen.
Der Konstruktor wird jedoch erst dann interessant, wenn man Parameter einsetzt; und das sieht so aus:

public class KlasseA
{
private int x;

public KlasseA(int wert)
{
x = wert;
}
}
public class KlasseB extends KlasseA
{ public KlasseB(int zahl)
{
super(zahl); }
}
In KlasseB wird der Konstruktor mit der Parameterliste (also mit int-Werten) der Oberklasse ausgerufen.

Polymorphie
Polymorphie (= Vielgestaltigkeit) ist eine weitere objektorientierte Methode von Java. Sie ermöglicht dynamisches Binden, d.h. der Compiler entscheidet zur Laufzeit dynamisch welche Methode er aufruft.
Das klingt jetzt komisch und bevor ich mit der eigentliche Polymorphie beginne muss ich noch eine weitere Technik einführen: die Typanpassung. Instanzen werden ja durch folgende Anweisung erzeugt: Klasse instanz = new Klasse();
Es ist jedoch auch möglich ein Objekt einer Unterklasse einem Objekt der Oberklasse zuzuweisen. Das sieht dann so aus:
Erbe instanz1 = new Erbe();
Ahn instanz2 = instanz1;

Man erzeugt also zuerst das Objekt instanz1 - das auf herkömmlichen Wege erstellt wurde - danach erzeugt man eine Referenz instanz2 der Klasse Ahn und lassen diese auf das Objekt instanz1 zeigen. Da das Erbe-Objekt ein spezialisiertes Ahn-Objekt ist, funktioniert diese Zuweisung. Das erscheint auf den ersten Blick blödsinnig! Jedoch übernimmt instanz2 alle Attribute und Methoden die Ober- und Unterklasse gemeinsam haben. Alle Attribute und Methoden die nach der Vererbung in die Unterklasse Erbe eingefügt wurden, werden also nicht in instanz2 übernommen.
Achtung! Es lässt sich immer nur eine Referenz von Oberklasse auf die Unterklasse legen. Es ist also nicht möglich eine Referenz vom Typ Erbe auf Ahn zu legen (folgende Anweisung ist also nicht möglich: Erbe instant1 = instanz2;). Hier gilt, dass die Typen unvereinbar sind.

Das war die Vorarbeit. Nun geht es an die eigentliche Polymorphie. Wir haben soeben definiert, dass bei der Typanpassung in das Oberklasseobjekt alle Attribute und Methoden übernommen werden, die Ober- und Unterklasse gemeinsam haben. Was aber ist, wenn alle Klassen die gleichen Attribute und Methoden besitzen und in den Unterklassen nur die Methoden überschrieben werden?
Was also macht man bei folgender Codierung:

Ahn a1 = new Erbe1();
Ahn a2 = new Erbe2();
System.out.println(a1.text());
System.out.println(a2.text());

Wird nun in beiden Fällen die Methode text() aus der Ahn-Klasse aufgerufen? NEIN! Der Compiler registriert zwar dass es sich um die Ahn-Klasse handelt, er erkennt jedoch auch dass ein Erbe-Objekt erzeugt wird.
Wie eingangs erwähnt entscheidet sich der Compiler dynamisch welche Methode aufzurufen ist. Die Polymorphie wurde also eingesetzt.

Related Workshops: Allgemeines \\ Java Einführung \\ Arbeit mit dem JCreator \\ Programmieren mit Java \\ Programmiergrundlagen \\ Grafische Programmierung \\ Datenbankprogrammierung
Related Files: JCreator LE

Workshop als PDF

<Zurück

© by www.abyter.de (Martin Monshausen)