Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 6 Eigene Klassen schreiben
gp 6.1 Eigene Klassen definieren
gp 6.1.1 Methodenaufrufe und Nebeneffekte
gp 6.1.2 Argumentübergabe mit Referenzen
gp 6.1.3 Die this-Referenz
gp 6.1.4 Überdeckte Objektvariablen nutzen
gp 6.2 Assoziationen zwischen Objekten
gp 6.3 Pakete
gp 6.3.1 Hierarchische Strukturen
gp 6.3.2 Paketnamen
gp 6.3.3 Eine Verzeichnisstruktur für eigene Projekte
gp 6.4 Privatsphäre und Sichtbarkeit
gp 6.4.1 Wieso nicht freie Methoden und Variablen für alle?
gp 6.4.2 Privat ist nicht ganz privat. Es kommt darauf an, wer's sieht
gp 6.4.3 Zugriffsmethoden für Attribute definieren
gp 6.4.4 Zusammenfassung zur Sichtbarkeit
gp 6.4.5 Sichtbarkeit in der UML
gp 6.5 Statische Methoden und Variablen
gp 6.5.1 Warum statische Eigenschaften sinnvoll sind
gp 6.5.2 Statische Eigenschaften mit static
gp 6.5.3 Statische Eigenschaften als Objekteigenschaften nutzen
gp 6.5.4 Statische Eigenschaften und Objekteigenschaften
gp 6.5.5 Statische Variablen zum Datenaustausch
gp 6.5.6 Warum die Groß- und Kleinschreibung wichtig ist
gp 6.5.7 Konstanten mit dem Schlüsselwort final bei Variablen
gp 6.5.8 Problem mit finalen Klassenvariablen
gp 6.5.9 Typsicherere Konstanten
gp 6.5.10 Statische Blöcke
gp 6.6 Objekte anlegen und zerstören
gp 6.6.1 Konstruktoren schreiben
gp 6.6.2 Einen anderen Konstruktor der gleichen Klasse aufrufen
gp 6.6.3 Initialisierung der Objekt- und Klassenvariablen
gp 6.6.4 Finale Werte im Konstruktor setzen
gp 6.6.5 Exemplarinitialisierer (Instanzinitialisierer)
gp 6.6.6 Zerstörung eines Objekts durch den Müllaufsammler
gp 6.6.7 Implizit erzeugte String-Objekte
gp 6.6.8 Zusammenfassung: Konstruktoren und Methoden
gp 6.7 Veraltete (deprecated) Methoden/Konstruktoren
gp 6.8 Vererbung
gp 6.8.1 Vererbung in Java
gp 6.8.2 Einfach- und Mehrfachvererbung
gp 6.8.3 Gebäude modelliert
gp 6.8.4 Konstruktoren in der Vererbung
gp 6.8.5 Sichtbarkeit
gp 6.8.6 Das Substitutionsprinzip
gp 6.8.7 Automatische und explizite Typanpassung
gp 6.8.8 Finale Klassen
gp 6.8.9 Unterklassen prüfen mit dem Operator instanceof
gp 6.8.10 Methoden überschreiben
gp 6.8.11 super: Aufrufen einer Methode aus der Oberklasse
gp 6.8.12 Nicht überschreibbare Funktionen
gp 6.8.13 Fehlende kovariante Rückgabewerte
gp 6.9 Die oberste aller Klassen: Object
gp 6.9.1 Klassenobjekte
gp 6.9.2 Objektidentifikation mit toString()
gp 6.9.3 Objektgleichheit mit equals() und Identität
gp 6.9.4 Klonen eines Objekts mit clone()
gp 6.9.5 Hashcodes
gp 6.9.6 Aufräumen mit finalize()
gp 6.9.7 Synchronisation
gp 6.10 Die Oberklasse gibt Funktionalität vor
gp 6.10.1 Dynamisches Binden als Beispiel für Polymorphie
gp 6.10.2 Keine Polymorphie bei privaten, statischen und finalen Methoden
gp 6.10.3 Polymorphie bei Konstruktoraufrufen
gp 6.11 Abstrakte Klassen
gp 6.11.1 Abstrakte Klassen
gp 6.11.2 Abstrakte Methoden
gp 6.11.3 Über abstract final
gp 6.12 Schnittstellen
gp 6.12.1 Ein Polymorphie-Beispiel mit Schnittstellen
gp 6.12.2 Die Mehrfachvererbung bei Schnittstellen
gp 6.12.3 Erweitern von Interfaces - Subinterfaces
gp 6.12.4 Vererbte Konstanten bei Schnittstellen
gp 6.12.5 Vordefinierte Methoden einer Schnittstelle
gp 6.12.6 CharSequence als Beispiel einer Schnittstelle
gp 6.13 Innere Klassen
gp 6.13.1 Statische innere Klassen und Schnittstellen
gp 6.13.2 Mitglieds- oder Elementklassen
gp 6.13.3 Lokale Klassen
gp 6.13.4 Anonyme innere Klassen
gp 6.13.5 Eine Sich-Selbst-Implementierung
gp 6.13.6 this und Vererbung
gp 6.13.7 Implementierung einer verketteten Liste
gp 6.13.8 Funktionszeiger
gp 6.14 Gegenseitige Abhängigkeiten von Klassen


Galileo Computing

6.5 Statische Methoden und Variablendowntop

Exemplarvariablen sind eng mit ihrem Objekt verbunden.1Wird ein Objekt geschaffen, erhält es einen eigenen Satz von Exemplarvariablen, die zusammen den Zustand des Objekts repräsentieren. Ändert eine Objektmethode den Wert einer Exemplarvariablen in einem Objekt, so hat dies keine Auswirkungen auf die Daten der anderen Objekte; jedes Objekt speichert eine individuelle Belegung. Es gibt jedoch auch Situationen, in denen Eigenschaften oder Methoden nicht direkt einem individuellen Objekt zugeordnet werden. Dazu gehören zum Beispiel die Methoden:

gp sin(), etwa in Math.sin(Math.PI/2.0)
gp max(), etwa in Math.max(1, -2)
gp Color.HSBtoRGB(), zum Konvertieren von Farben in Farbräumen
gp Integer.parseInt(), Umwandeln von einem String in den Integer oder in Variablen, die sogar konstant sein können
gp MAX_INTEGER, die größte darstellbare Zahl
gp PI aus Math bestimmt die Zahl 3,1415 ...

Abbildung
Hier klicken, um das Bild zu Vergrößern

Diese genannten Eigenschaften sind weniger einem konkreten Objekt mit seinem ureigenen Objektzustand zuzuordnen, als vielmehr der Klasse. Diese Art von Zugehörigkeit wird in Java durch statische Eigenschaften unterstützt. Da sie nicht zu einem Objekt gehören wie Objekteigenschaften, nennen wir sie auch Klasseneigenschaften. Die Sinus-Funktion ist ein Beispiel für eine statische Methode der Mathe-Klasse und MAX_INTEGER ein statisches Attribut der Klasse Integer.


Galileo Computing

6.5.1 Warum statische Eigenschaften sinnvoll sinddowntop

Statische Eigenschaften haben gegenüber Objekteigenschaften den Vorteil, dass sie im Programm ausdrücken, keinen Zustand vom Objekt zu nutzen. Betrachten wir noch einmal Funktionen aus der Mathe-Klasse. Wenn sie Objektmethoden wären, so würden sie in der Regel mit einem Objektzustand arbeiten. Die Funktionen nähmen dann keinen Parameter, sondern arbeiteten mit dem internen Zustand des aufrufenden Objekts. Das macht aber keine Mathe-Funktion. Um den Sinus eines Winkels zu berechnen, benötigen wir kein spezifisches Mathe-Objekt. Statische Funktionen sind aus diesem Grunde häufiger als statische Variablen, da sie ihre Arbeitswerte ausschließlich aus den Parametern ziehen. Statische Variablen werden in erster Linie als Konstanten verwendet.


Galileo Computing

6.5.2 Statische Eigenschaften mit staticdowntop

Um statische Eigenschaften in Java umzusetzen, fügen wir vor der Definition einer Variablen oder einer Methode das Schlüsselwort static hinzu. Für den Zugriff verwenden wir einfach den Klassennamen, den wir wie eine Referenz verwenden. In der UML können statische Eigenschaften durch Unterstreichen markiert werden.


Beispiel Eine statische Funktion und eine statische Variable

Listing 6.10 DiskoUtensilien.java

public class DiskoUtensilien
{
  /**
   * Platz, die jede Person benötigt.
   */
  public final static double PLATZ_PRO_PERSON = 5 /* Quadratmeter */;
  
  /**
   * Platz, die eine gegebene Anzahl Personen in einer Disko benötigen.
   * 
   * @param anzahl  Anzahl Personen.
   * @return        Quadratmeter.
   */
  public static double platzFuerPersonen( int anzahl )
  {
    return anzahl * PLATZ_PRO_PERSON;
  }
}

Die Eigenschaften können nun leicht mit dem Namen DiskoUtensilien angesprochen werden:

System.out.println( DiskoUtensilien.platzFuerPersonen(290) );


Galileo Computing

6.5.3 Statische Eigenschaften als Objekteigenschaften nutzendowntop

Besitzt eine Klasse eine Klasseneigenschaft, so kann sie auch wie ein Objektattribut über die Referenz angesprochen werden. Das bedeutet, dass es zwei Möglichkeiten gibt, wenn ein Objektexemplar existiert und die Klasse ein statisches Attribut hat. Bleiben wir bei unserem obigen Beispiel mit der Klasse DiskoUtensilien. Jetzt können wir für den Zugriff auf PLATZ_PRO_PERSON schreiben:

DiskoMitStatics d = new DiskoUtensilien();
System.out.println( d.PLATZ_PRO_PERSON );               // keine gute Idee
System.out.println( DiskoUtensilien.PLATZ_PRO_PERSON ); // das ist gut so

Die unteren beiden Anweisungen sind identisch. Betrachten wir alleine dieses Codesegment, so ist für uns nicht sichtbar, dass PLATZ_PRO_PERSON eine statische Variable ist. Aus diesem Grund sei der Tipp gegeben, statische Eigenschaften über ihren Klassennamen anzusprechen. Falls eine Klasse nur statische Attribute definiert, so spricht nichts dagegen einen privaten Konstruktor anzugeben - Exemplare werden damit vermieden.


Galileo Computing

6.5.4 Statische Eigenschaften und Objekteigenschaftendowntop

Wie wir oben gesehen haben, können wir über eine Objektreferenz auch statische Eigenschaften nutzen. Wir wollen uns aber noch einmal vergewissern, wie Objekteigenschaften und statische Eigenschaften gemischt werden können. Erinnern wir uns daran, dass unsere ersten Programme aus der main()-Methode bestanden, aber unsere anderen Methoden auch static sein mussten. Dies ist sinnvoll, denn eine statische Methode kann - ohne explizite Angabe eines aufrufenden Objekts - nur andere statische Methoden aufrufen. Wie sollte auch eine statische Methode eine Objektmethode aufrufen können, wenn es kein dazugehöriges Objekt gibt? Statische Methoden gibt es immer, wenn es die Klasse gibt. Andersherum kann aber jede Objektmethode eine beliebige statische Methode direkt aufrufen. Genauso verhält es sich mit Attributen. Eine statische Methode kann keine Objektattribute nutzen, da es kein implizites Objekt gibt, auf dessen Eigenschaften zugegriffen werden könnte.

this-Referenzen und statische Eigenschaften

Auch der Einsatz der this-Referenz ist bei statischen Eigenschaften nicht möglich. Das trifft in erster Linie statische Methoden, die eine this-Referenz verwenden wollen.


Hinweis In statischen Methoden gibt es kein this

class InStaticNoThis
{
  int a;
  static void martina()
  {
    this.a = 1;           // Compilerfehler genauso wie a = 1
  }
}

Galileo Computing

6.5.5 Statische Variablen zum Datenaustauschdowntop

Der Wert einer statischen Variablen wird bei dem Klassenobjekt gespeichert und nicht bei einem Exemplar der Klasse. Wie wir aber gesehen haben, kann jedes Exemplar einer Klasse auch auf die statischen Variablen der Klasse zugreifen. Da eine statische Variable aber nur einmal pro Klasse vorliegt, führt dies dazu, dass mehrere Objekte sich eine Variable teilen. Somit wird ein Austausch von Informationen über die Objektgrenze hinaus erlaubt. Doch kein Vorteil ohne Nachteil. Es kann bei nebenläufigen Zugriffen zu Problemen kommen. Deshalb müssen wir spezielle Synchronisationsmechanismen nutzen.

Abbildung
Hier klicken, um das Bild zu Vergrößern


Beispiel Objekte tauschen Daten über eine gemeinsame statische Variable.

Listing 6.11 ShareData.java

class ShareData
{
  private static int share;
  public void memorize( int i )
  {
    share = i;
  }
  public int retrieve ()
  {
    return share;
  }
  public static void main( String args[] )
  {
    ShareData s1 = new ShareData();
    ShareData s2 = new ShareData();
    s1.memorize( 2 );
    System.out.println( s2.retrieve() );    // ist 2
  }
}


Galileo Computing

6.5.6 Warum die Groß- und Kleinschreibung wichtig istdowntop

Die Vorgabe der Namenskonvention sagt, Klassennamen sind mit Großbuchstaben zu vergeben und Variablennamen mit Kleinbuchstaben. Treffen wir auf eine Anweisung wie Math.max(a, b), so wissen wir sofort, dass max() eine statische Methode sein muss, weil davor ein Bezeichner steht, der großgeschrieben ist. Dieser kennzeichnet also keine Referenz, sondern einen Klassennamen. Daher sollten wir in unseren Programmen großgeschriebene Objektnamen meiden.


Beispiel Warum Referenzvariablen mit Kleinbuchstaben und Klassennamen mit Großbuchstaben beginnen sollten.
String StringModifier = "What is the Matrix?";
String t = StringModifier.trim();
Die trim()-Methode ist nicht statisch, wie die Anweisung durch die Großschreibung der Variablen suggeriert. Das gleiche Problem haben wir, wenn wir Klassen mit Kleinbuchstaben benennen. Auch das kann irritieren.
class turnbeutel
{
  static void vergessen() { ... }
}
Jetzt könnte jemand turnbeutel.vergessen() schreiben, und der Leser würde annehmen, dass turnbeutel eine Referenz ist, da sie kleingeschrieben ist, und vergessen() eine Objektmethode. Wir sehen an diesem Beispiel, dass es wichtig ist, die Namensgebung zu verfolgen.


Galileo Computing

6.5.7 Konstanten mit dem Schlüsselwort final bei Variablendowntop

In Programmen gibt es Variablen, die sich ändern, wie ein Schleifenzähler, aber auch andere, die sich beim Ablauf eines Programms nicht ändern. Dazu gehören etwa die Anzahl Buchstaben in ›Nichts als die Wahrheit‹ - zumindest in der ersten Ausgabe - oder die Ausmaße einer DIN-A4-Seite2. Die Werte sollten nicht wiederholt im Quellcode stehen, sondern über ihren Namen angesprochen werden. Dazu werden Variablen definiert, denen genau der konstante Wert zugewiesen wird; die Konstanten heißen dann symbolische Konstanten.

Statische Variablen werden auch verwendet, um symbolische Konstanten zu definieren. Damit die Variablen unveränderlich blieben, gesellt sich zusätzlich der Modifizier final dazu. Dem Compiler wird auf diese Weise mitgeteilt, dass dieser Variablen nur einmal ein Wert zugewiesen werden darf. Für Variablen bedeutet dies: Es sind Konstanten, jeder spätere Schreibzugriff wäre ein Fehler.

Listing 6.12 Genre.java

public class Genre
{
  public final static int CHRISTIAN_GANGSTA_RAP  = 0;
  public final static int COUNTRY                = 1;
  public final static int GANGSTA                = 2;
  public final static int JUNGLE                 = 3;
  public final static int JPOP                   = 4;
  public final static int GOTHIC_TECHNO          = 5;
  public final static int POLKA                  = 6;
  public final static int PSYCHEDELIC_CLASSIC    = 7;
  public final static int TECHNO                 = PSYCHEDELIC_CLASSIC + 1;
}

In der Klasse Genre werden mehrere Konstanten definiert. Für Konstanten ist es günstig, sie relativ zum Vorgänger zu wählen, um das Einfügen in der Mitte zu vereinfachen. Das sehen wir bei der letzen Variable TECHO. Da im Quellcode das vorkommen der Zahlen 2, 4, 5 undurchsichtig wäre, sind symbolische Namen zwingend. Stehen dennoch Zahlen ohne öffentliche Bedeutung im Quellcode, so werden sie magische Zahlen (engl. magic numbers) genannt.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 6.5 Die Genre-Klasse in einer alternativen ‚Eclipse-Darstellung'

Eine in der Sprache Java verankerte Möglichkeit zur Definition von Konstanten wird es in Java 1.5 mit enum geben.


Tipp Es ist eine gute Idee, die Namen von Konstanten vollständig großzuschreiben, um deren Bedeutung hervorzuheben.


Galileo Computing

6.5.8 Problem mit finalen Klassenvariablendowntop

Finale Klassenvariablen können in der Entwicklung mit einer größeren Anzahl von Klassen zu einem Problem werden. Das liegt an der Eigenschaft der finalen Werte, dass sie sich nicht ändern können und sich daher sicher an der Stelle einsetzen lassen, wo sich gebraucht werden. Ein Beispiel:

class Finanz
{
  public final static int MWST = 16;
}

Greift eine andere Klasse auf die Variable MWST zu, so ist das im Quellcode nicht als direkter Variablenzugriff Finanz.MWST kodiert, sondern das Literal 16 wird direkt an der Aufrufstelle eingesetzt. Das ist eine Optimierung des Compilers, die er laut Java-Definition machen kann.

Das ist zwar nett, bringt aber gewaltige Probleme mit sich, etwa dann, wenn sich die Konstante einmal ändert. Dann muss nämlich auch jede Klasse übersetzt werden, die Bezug auf die Konstante hatte. Falls die abhängigen Klassen nicht neu übersetzt würden, würden sie mit dem alten eincompilierten Wert arbeiten.

Die Lösung ist, die bezugnehmenden Klassen neu zu übersetzen und sich am Besten anzugewöhnen, bei einer Änderung einer Konstante gleich alles neu zu compilieren. Ein anderer Weg transformiert die finale Variable in eine später initialisierte Form:

class Finanz
{
  public final static int MWST = new Integer( 16 ).intValue();
}

Die Initialisierung findet in jedem Konstruktor statt und die Konstante mit dem Literal ist erst einmal weg. Der Compiler wird also Finanz.MWST nicht als 16 vorfinden und daher das Literal an den Aufrufstellen nicht einbauen. In der Klassendatei wird der Bezug Finanz.MWST weiterhin zu finden sein, und eine Änderung der Konstante ist für alle Nutzer deutlich.


Galileo Computing

6.5.9 Typsicherere Konstantendowntop

Konstanten sind eine wertvolle Möglichkeit, den Quellcode aussagekräftiger zu machen. Der herkömmliche Weg geht über Ganzzahl-Konstanten:

public final int KONSTANTE1 = 0;
public final int KONSTANTE2 = 1;
public final int KONSTANTE3 = 2;

Dieser Weg bringt den Nachteil mit sich, dass die Konstanten nicht unbedingt von jedem angewendet werden müssen und ein Programmierer eventuell direkt die Zahlen oder Zeichenketten einsetzt. Dieses Problem kommt zum Beispiel auf, wenn ein Font-Objekt für die grafische Oberfläche angelegt werden soll, aber unser Gedächtnis versagt, in welcher Reihenfolge die Parameter einzugeben sind. Ein Fallbeispiel:

Font f = new Font( "Dialog",  12, Font.BOLD );

Leider ist dieses falsch, denn die Parameter für die Zeichensatzgröße und den Schriftstil sind vertauscht. Das Problem ist, dass die Konstanten nur Namen für Werte eines frei zugänglichen Grundtyps sind, und nur der Wert an die Funktion übergeben wird. Niemand kann verbieten, dass direkt die Werte eingetragen werden. Das führt dann zu Fehlern, wie im oberen Fall. In diesem ist 12 die Ganzzahl für den Schriftstil, obwohl es dafür nur die Werte 0, 1, 2 geben sollte. Mit Zeichenketten als Wert der Konstanten kommen wir der Lösung auch nicht näher.

Eine gute Möglichkeit, von Ganzzahlen wegzukommen, ist, Objekte einer Klasse als Konstanten einzusetzen. Folgendes bietet sich an:

Listing 6.13 TypsicherGenre.java

public final class TypsicherGenre
{
  public static final TypsicherGenre COUNTRY = new TypsicherGenre();
  public static final TypsicherGenre TECHNO  = new TypsicherGenre();
  private int id;
  private static int nextId;
  private TypsicherGenre()  // von aussen lassen sich keine weiteren
  {                         // Objekte erzeugen
    id = nextId++;
  }
}

Die Klasse TypsicherGenre definiert die Konstanten als statische Attribute vom Typ TypsicherGenre. Da die Objekte für die Konstanten aber nur einmal vorliegen, lassen sie sich einfach mit ==, wie im folgenden Beispiel mit func() gezeigt, vergleichen.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Listing 6.14 TypsicherGenre.java

public class TypsichereKonstantenDemo
{
  static void func( TypsicherGenre k )
  {
    if ( k == TypsicherGenre.COUNTRY )
      System.out.println( "GEKRINGELT" );
    if ( k == TypsicherGenre.TECHNO )
      System.out.println( "GESTRICHELT" );
  }
  
  public static void main( String args[] )
  {
    func( TypsicherGenre.TECHNO );
  }
}

Galileo Computing

6.5.10 Statische Blöcketoptop

Eine Art Konstruktor für das Klassenobjekt selbst (nicht die Exemplare der Klasse) ist ein static-Block, der in jede Klasse gesetzt werden kann. Der Block wird genau dann ausgeführt, wenn die Klasse vom Klassenlader in die virtuelle Maschine geladen wird. In der Regel geschieht das nur einmal während eines Programmlaufs. Unter gewissen Umständen - ein eigener Klassenlader für die Klasse - kann jedoch eine Klasse auch aus dem Speicher entfernt werden und dann mit einem anderen Klassenlader wieder neu geladen werden.


Beispiel Zwei statische Blöcke mit einer Hauptfunktion

Listing 6.15 StaticBlock.java

class StaticBlock
{
  static
  {
    System.out.println( "Eins" );
  }
  static
  {
    System.out.println( "Zwei" );
  }

  public static void main( String args[] )
  {
    System.out.println( "Jetzt geht's los." );
  }
}

Lädt der Klassenlader die Klasse StaticBlock, so führt er zuerst den ersten Block mit der Ausgabe »Eins« aus und dann den Block mit der Ausgabe »Zwei«. Da die Klasse StaticBlock auch das main() besitzt, führt die virtuelle Maschine anschließend die Start-Funktion aus.


Beispiel Mit diesem Trick lassen sich auch Programme ohne main()-Funktion schreiben. In den statischen Block wird einfach das Hauptprogramm geschrieben. Da jedoch die virtuelle Maschine immer noch nach dem main() sucht, müssen wir die Laufzeitumgebung schon vorher beenden. Dies geschieht dadurch, dass mit System.exit() die Bearbeitung abgebrochen wird:

Listing 6.16 StaticNowMain.java

class StaticNowMain
{
  static
  {
    System.out.println( "Jetzt bin ich das Hauptprogramm" );
    System.exit( 0 );
  }
}
Nicht jede Laufzeitumgebung nimmt das jedoch ohne Murren hin. Weiterhin ist mit diesem Vorgehen der Nachteil verbunden, dass bei Ausnahmen im versteckten Hauptprogramm manche virtuellen Maschinen unsinnige Fehler melden. Etwa, dass die Klasse StaticNowMain nicht gefunden wurde, oder auch eine ExceptionInInitializerError, die statt einer vernünftigen Exception kommt.






1 Das Symbol beziehungsweise diese Sichtbarkeit ist erst seit der UML-Spezifikation 1.4 definiert.

2 Ein DIN-A4-Blatt ist 29.7 Zentimeter hoch und 21.0 Zentimeter breit.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de