cover
Michael Ziegenbalg

Programmieren in Java für Fortgeschrittene





BookRix GmbH & Co. KG
80331 München

Programmieren in Java für Fortgeschrittene

Java für Fortgeschrittene

Neben der Markierung zu statischen Methoden gibt es noch eine Reihe von Schlüsselworten, die sich eher dem fortgeschrittenen Entwickler erschließen.

Es sind dies in erster Linie besondere Deklarationsmöglichkeiten für Methoden und Variablen, die entweder der Optimierung für die Ausführung oder auch der Strukturierung dienen.

Abstrakte Methoden und Klassen

Abstrakte Methoden und Klassen

 

Es besteht die Möglichkeit, Superklassen so zu definieren, daß erst die Subklassen die Definition mit Leben füllen müssen. Zu erkennen sind abstrakte Deklarationen an den leeren Beschreibungen der Methoden.

 

abstract cl0ass vehikel {

abstract public void fahren() ;

}

class auto extends vehikel {

public void fahren () {

... // zuvor abstrakte Methode wird
// hier mit ausgefüllt mit Statements

}

}

 

Abstrakte Klassen können nicht instantisiert werden. Was sollte auch geschehen,. Private Methoden können im Übrigen nicht abstrakt sein, da diese dann nicht weitervererbt werden können. Auch statische Methoden und Konstruktoren sind als abstrakte Methoden ungeeignet.

In Bezug auf die Vererbung verhalten sich abstrakte Klassen wie folgt: Solange die Subklassen nicht die abstrakten Methoden mit einer Beschreibung ausfüllen, gelten die Subklassen ebenfalls als abstrakte Klassen. Abstrakte Methoden können keine Methoden überschreiben, die in Superklassen definiert sind.

 

 

Die Interfaces

 

Eine besondere Form der abstrakten Klasse ist ein Interface. Es läßt sich wie eine reguläre Klasse vererben. Eine besondere Kraft gewinnt dieses Konstrukt, wenn bei der Verererbung von regulären Klassen zusätzlich noch Methoden eines oder mehreren Interfaces übernommen werden. Interfaces tragen vereinbarungsgemäß im Englischen einen Namen wie Runable, Printable oder Observable.

 

public interface Printable {

public abstrakt void print();

}

Eine Klasse, die sich der Methode print() bedienen will, muß das Interface mit dem Schlüsselwort implements in die Implementation der Klasse integrieren.

 

 

class xxx extends yyy implements Printable {

public void print () {
System.out.println(...);
}
public void methoden () { ... }

}

 

Die Benutzung von Interfaces ist teilweise vergleichbar mit „Multiple Inheritance“ , der Vererbung aus mehreren Klassen in C++, da es die Möglichkeit der Übernahme von Schnittstellen aus anderen Klassen bietet.

Interfaces sind aber weder Objekte noch Klassen sondern eher ein Kontrakt, der die Klasse, die ein Interface implementiert, dazu verpflichtet, die abstrakten Methoden des Interfaces mit Leben zu füllen. Gerade bei der Java-Programmierung in WWW – Seiten mit Hilfe von Java-Applets wird ausgiebig von diesem Konstrukt Gebrauch gemacht.

 

class meinapplet extends applet implements Runnable{ ... };

 

um in Zusammenarbeit mit dem Scheduler Leben in die HTML-Seite zu bringen.
Die Klasse meinapplet verpflichtet sich bei Übernahme des Interfaces Runnable die Methode run() zu implementieren, die der Scheduler dann immer wieder aufruft.

Die Native Methoden

 Die Native Methoden

 

Es ist denkbar, daß der Programmierer auf Routinen zurückzugreifen möchte, welche in C und C++ geschrieben worden sind. Mit nativen Methoden ist eine Schnittstelle zwischen Java und plattformabhängigen Prozeduren geschaffen worden. Die Integration erfolgt über dynamisch ladbare Bibliotheken.

 

native double cos (double cos);

 

Auf diese Art und Weise sind z.B. die mathematischen Funktionen, die bereits als ladbare Bibliotheken im System vorhanden sind, in die Laufzeitumgebung von Java integriert.

Bei der Verwendung von nativen Methoden sollte man sich im Klaren darüber sein, daß damit die Übertragbarkeit des Java-Programms auf beliebige Zielsystem durch die Verfügbarkeit der eigenen ladbaren Bibliothek auf dieser Plattform bestimmt wird.

 

Schlüsselwörter

 Das Schlüsselwort synchronized

 

Wenn man die Paralellverarbeitung programmiert, hat man sehr schnell mit dem Problem der Sychronisation von Abläufen und Zugriffen auf Variablen zu tun. Mit dem Schlüsselwort

 

synchronized

 

werden die Instanzen und Methoden markiert, die den nahezu parallelen Zugriff auf sich zulassen. Im einem folgendem Abschnitt wird der Einsatz von parallelen Threads in Java-Programmen näher diskutiert.

 

Das Schlüsselwort threadsafe

 

C/C++ Programmierer kennen das Schlüsselwort register, daß dem Compiler den Hinweis gibt, eine Variable nicht auf dem Stack abzulegen, sondern wenn möglich nur in Registern der CPU zwischenzuspeichern. Dies erhöht die Verarbeitungsgeschwindigkeit beträchtlich.

Einen ähnlichen Effekt kann man unter Java durch die Kennzeichnung von Variablen mit dem Schlüsselwort „threadsafe“ erreichen. Es ist ein Hinweis des Entwicklers an den Interpreter, daß diese Variable nie von mehreren Threads gleichzeitig manipuliert wird.

Andernfalls müßte jede Änderung auf dem Stack propagiert werden, da die Register der CPU zwischen verschiedenen Threads nicht errichbar sind.

 

Das Schlüsselwort final

 

Es macht sowohl dem Compiler als auch später dem Laufzeitsystem weniger Arbeit, wenn sie wissen, daß keine Subklassen erzeugt werden dürfen. Hinzu kommt noch ein Sicherheitsaspekt: Die Definition einer sensitiven Methode (z.B. die Passwortüberprüfung mit anschließender Authorisierung) könnte in einer Subklasse überlagert werden. Ein Entwickler kann dieses potentielle Sicherheitsloch stopfen, in dem er seine Implementation vor Uberlagerung schützt.

 

final void checkpasswd ()

 

Definition von Konstanten

 

Eine Variable, die in Subklassen nicht überschrieben werden kann, hat die Funktion einer Konstante.

Ein Beispiel findet sich in der Klasse der mathematischen Funktion in der Zahl ¸:

 

class math { // Klasse für mathematische Funktionen
...
final double PI = 3.1414.... ;

 

transient

Alle Instanzen eines Java-Programmes existieren nur zur Laufzeit. Wenn Objekte in Datenbanken geschrieben werden und von dort wieder gelesen werden spricht man von persistenten Objekten. Mit dem Schlüsselwort 'transient' können Variablen markiert werden, die persistent sein sollen.

 

transient LKW man = new LKW();

 

Die Markierung als persistentes Objekt ist eine Unterstützung für den Interpreter, der die Instanzvariablen entsprechend behandeln kann. Das Schlüsselwort transient ist eine transparente Optimierungsmöglichkeit für den Interpreter.

 

Was könnten C-/C++-Programmierer vermissen

 

 

Zeiger

 Zeiger

Es gibt keinen Zugriff auf Adressen , wie über Zeiger (wie z.B. int*a; struct b *c;) dei C oder C++. Der Hauptgrund für die Entscheidung, diese Konstrukte in Java nicht zuzulassen, liegt darin, bereits bei der Definition der Sprache einige der Hauptfehlerquellen bei C/C++ Programmierung zu eliminieren.