Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort

Download:
- ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel (8. Auflage)

Java ist auch eine Insel (8. Aufl.)
8., aktual. Auflage, geb., mit DVD
1.475 S., 49,90 Euro
Galileo Computing
ISBN 978-3-8362-1371-4
Pfeil 6 Eigene Klassen schreiben
Pfeil 6.1 Eigene Klassen mit Eigenschaften deklarieren
Pfeil 6.1.1 Attribute deklarieren
Pfeil 6.1.2 Methoden deklarieren
Pfeil 6.1.3 Die this-Referenz
Pfeil 6.2 Privatsphäre und Sichtbarkeit
Pfeil 6.2.1 Für die Öffentlichkeit: public
Pfeil 6.2.2 Kein Public Viewing – Passwörter sind privat
Pfeil 6.2.3 Wieso nicht freie Methoden und Variablen für alle?
Pfeil 6.2.4 Privat ist nicht ganz privat: Es kommt darauf an, wer’s sieht
Pfeil 6.2.5 Zugriffsmethoden für Attribute deklarieren
Pfeil 6.2.6 Setter und Getter nach der JavaBeans-Spezifikation
Pfeil 6.2.7 Paketsichtbar
Pfeil 6.2.8 Zusammenfassung zur Sichtbarkeit
Pfeil 6.3 Statische Methoden und statische Attribute
Pfeil 6.3.1 Warum statische Eigenschaften sinnvoll sind
Pfeil 6.3.2 Statische Eigenschaften mit static
Pfeil 6.3.3 Statische Eigenschaften über Referenzen nutzen?
Pfeil 6.3.4 Warum die Groß- und Kleinschreibung wichtig ist
Pfeil 6.3.5 Statische Variablen zum Datenaustausch
Pfeil 6.3.6 Statische Eigenschaften und Objekteigenschaften
Pfeil 6.4 Konstanten und Aufzählungen
Pfeil 6.4.1 Konstanten über öffentliche statische finale Variablen
Pfeil 6.4.2 Eincompilierte Belegungen der Klassenvariablen
Pfeil 6.4.3 Typ(un)sichere Aufzählungen
Pfeil 6.4.4 Aufzählungen mit enum
Pfeil 6.5 Objekte anlegen und zerstören
Pfeil 6.5.1 Konstruktoren schreiben
Pfeil 6.5.2 Der Default-Konstruktor
Pfeil 6.5.3 Parametrisierte und überladene Konstruktoren
Pfeil 6.5.4 Copy-Konstruktor
Pfeil 6.5.5 Einen anderen Konstruktor der gleichen Klasse aufrufen
Pfeil 6.5.6 Ihr fehlt uns nicht – der Garbage-Collector
Pfeil 6.5.7 Private Konstruktoren, Utility-Klassen, Singleton, Fabriken
Pfeil 6.6 Klassen- und Objektinitialisierung
Pfeil 6.6.1 Initialisierung von Objektvariablen
Pfeil 6.6.2 Statische Blöcke als Klasseninitialisierer
Pfeil 6.6.3 Initialisierung von Klassenvariablen
Pfeil 6.6.4 Exemplarinitialisierer (Instanzinitialisierer)
Pfeil 6.6.5 Finale Werte im Konstruktor und in statischen Blöcken setzen
Pfeil 6.7 Assoziationen zwischen Objekten
Pfeil 6.7.1 Unidirektionale 1:1-Beziehung
Pfeil 6.7.2 Bidirektionale 1:1-Beziehungen
Pfeil 6.7.3 Unidirektionale 1:n-Beziehung
Pfeil 6.8 Vererbung
Pfeil 6.8.1 Vererbung in Java
Pfeil 6.8.2 Spielobjekte modelliert
Pfeil 6.8.3 Implizite Basisklasse java.lang.Object
Pfeil 6.8.4 Einfach- und Mehrfachvererbung
Pfeil 6.8.5 Sichtbarkeit protected
Pfeil 6.8.6 Konstruktoren in der Vererbung und super
Pfeil 6.9 Typen in Hierarchien
Pfeil 6.9.1 Automatische und explizite Typanpassung
Pfeil 6.9.2 Das Substitutionsprinzip
Pfeil 6.9.3 Typen mit dem binären Operator instanceof testen
Pfeil 6.10 Methoden überschreiben
Pfeil 6.10.1 Methoden in Unterklassen mit neuem Verhalten ausstatten
Pfeil 6.10.2 Mit super an die Eltern
Pfeil 6.10.3 Finale Klassen und finale Methoden
Pfeil 6.10.4 Kovariante Rückgabetypen
Pfeil 6.10.5 Array-Typen und Kovarianz
Pfeil 6.11 Dynamisches Binden/Polymorphie
Pfeil 6.11.1 Unpolymorph bei privaten, statischen und finalen Methoden
Pfeil 6.11.2 Polymorphie bei Konstruktoraufrufen
Pfeil 6.12 Abstrakte Klassen und abstrakte Methoden
Pfeil 6.12.1 Abstrakte Klassen
Pfeil 6.12.2 Abstrakte Methoden
Pfeil 6.13 Schnittstellen
Pfeil 6.13.1 Deklarieren von Schnittstellen
Pfeil 6.13.2 Implementieren von Schnittstellen
Pfeil 6.13.3 Markierungsschnittstellen
Pfeil 6.13.4 Ein Polymorphie-Beispiel mit Schnittstellen
Pfeil 6.13.5 Die Mehrfachvererbung bei Schnittstellen
Pfeil 6.13.6 Keine Kollisionsgefahr bei Mehrfachvererbung
Pfeil 6.13.7 Erweitern von Interfaces – Subinterfaces
Pfeil 6.13.8 Vererbte Konstanten bei Schnittstellen
Pfeil 6.13.9 Abstrakte Klassen und Schnittstellen im Vergleich
Pfeil 6.14 Dokumentationskommentare mit JavaDoc
Pfeil 6.14.1 Einen Dokumentationskommentar setzen
Pfeil 6.14.2 Mit javadoc eine Dokumentation erstellen
Pfeil 6.14.3 HTML-Tags in Dokumentationskommentaren
Pfeil 6.14.4 Generierte Dateien
Pfeil 6.14.5 Dokumentationskommentare im Überblick
Pfeil 6.14.6 JavaDoc und Doclets
Pfeil 6.14.7 Veraltete (deprecated) Typen und Eigenschaften


Galileo Computing - Zum Seitenanfang

6.6 Klassen- und Objektinitialisierung Zur nächsten ÜberschriftZur vorigen Überschrift

Eine wichtige Eigenschaft guter Programmiersprachen ist ihre Fähigkeit, keine uninitialisierten Zustände zu erzeugen. Bei lokalen Variablen achtet der Compiler auf die Belegung, also ob vor dem ersten Lesezugriff schon ein Wert zugewiesen ist. Bei Objektvariablen und Klassenvariablen haben wir bisher festgestellt, dass die Variablen automatisch mit 0, null oder false oder mit einem eigenen Wert belegt werden. Wir wollen jetzt sehen, wie dies genau funktioniert.


Galileo Computing - Zum Seitenanfang

6.6.1 Initialisierung von Objektvariablen Zur nächsten ÜberschriftZur vorigen Überschrift

Wenn der Compiler eine Klasse mit Objekt- oder Klassenvariablen sieht, dann müssen diese Variablen an irgendeiner Stelle initialisiert werden. Werden sie einfach deklariert und nicht mit einem Wert initialisiert, so regelt die virtuelle Maschine die Vorbelegung. Spannender ist der Fall, wenn den Variablen explizit ein Wert zugewiesen wird (der auch 0 sein kann). Dann erzeugt der Compiler automatisch einige zusätzliche Zeilen.

Betrachten wir dies zuerst für eine Objektvariable:

Listing 6.37 InitObjectVariable.java

class InitObjectVariable 
{ 
  int j = 1; 
 
  InitObjectVariable() 
  { 
    // Nothing to add 
  } 
 
  InitObjectVariable( int j ) 
  { 
    this.j = j; 
  } 
 
  InitObjectVariable( int x, int y ) 
  { 
    // Nothing to add 
  } 
}

Die Variable j wird mit 1 belegt. Es ist wichtig zu wissen, an welcher Stelle Variablen ihre Werte bekommen. So erstaunlich es klingt, aber die Zuweisung findet im Konstruktor statt. Das heißt, der Compiler wandelt das Programm bei der Übersetzung eigenmächtig wie folgt um:

class InitObjectVariable 
{ 
  int j; 
  InitObjectVariable() 
  { 
    j = 1; 
  } 
 
  InitObjectVariable( int j ) 
  { 
    this.j = 1; 
    this.j = j; 
  } 
 
  InitObjectVariable( int x, int y ) 
  { 
    j = 1; 
  } 
}

Wir erkennen, dass die Variable wirklich nur bei Aufruf des Konstruktors initialisiert wird. Die Zuweisung steht dabei in der ersten Zeile. Dies kann sich als Falle erweisen, denn problematisch ist etwa die Reihenfolge der Belegung.

Manuelle Nullung

Genau genommen initialisiert die Laufzeitumgebung jede Objekt- und Klassenvariable zunächst mit 0, null oder false und später mit einem Wert. Daher ist die Nullung von Hand nicht nötig:

class NeedlessInitNull 
{ 
  int    i = 0;                  // unnötig 
  String s = null;               // unnötig 
}

Der Compiler würde nur zusätzlich in jeden Konstruktor die Initialisierung i = 0, s = null einsetzen. [Wir wollen hier den Fall, dass der Konstruktor der Oberklasse i einen Wert ungleich 0 setzt, nicht betrachten.] Aus diesem Grund ist auch Folgendes nicht meisterhaft:

class NeedlessInitNull 
{ 
  int i = 0; 
  NeedlessInitNull( int i ) { this.i = i; } 
}

Die Belegung für i wird sowieso überschrieben.


Galileo Computing - Zum Seitenanfang

6.6.2 Statische Blöcke als Klasseninitialisierer Zur nächsten ÜberschriftZur vorigen Überschrift

Eine Art Konstruktor für das Klassenobjekt selbst (nicht die Exemplare der Klasse) ist ein static-Block, der einmal oder mehrmals in eine Klasse gesetzt werden kann. Jeder Block wird genau dann ausgeführt, wenn die Klasse vom Klassenlader in die virtuelle Maschine geladen wird. [In der Regel geschieht dies 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 und dann mit einem anderen Klassenlader wieder neu geladen werden. Dann werden die static-Blöcke neu ausgeführt.] Der Block heißt Klasseninitialisierer oder statischer Initialisierungsblock.

Listing 6.38 StaticBlock.java

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

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 Startfunktion aus.


Galileo Computing - Zum Seitenanfang

6.6.3 Initialisierung von Klassenvariablen Zur nächsten ÜberschriftZur vorigen Überschrift

Abschließend bleibt die Frage, wo Klassenvariablen initialisiert werden. Im Konstruktor ergibt dies keinen Sinn, da für Klassenvariablen keine Objekte angelegt werden müssen. Dafür gibt es den static{}-Block. Dieser wird immer dann ausgeführt, wenn der Klassenlader eine Klasse in die Laufzeitumgebung geladen hat. Für eine statische Initialisierung wird also wieder der Compiler etwas einfügen.


public class InitStaticVariable 
{ 
  static int staticInt = 2; 
}
public class InitStaticVariable 
{ 
  static int staticInt; 
  static 
  { 
    staticInt = 2; 
  } 
}


Galileo Computing - Zum Seitenanfang

6.6.4 Exemplarinitialisierer (Instanzinitialisierer) Zur nächsten ÜberschriftZur vorigen Überschrift

Neben den Konstruktoren haben die Sprachschöpfer eine weitere Möglichkeit vorgesehen, um Objekte zu initialisieren. Diese Möglichkeit wird insbesondere bei anonymen, inneren Klassen wichtig, also bei Klassen, die sich in einer anderen Klasse befinden.

Ein Exemplarinitialisierer ist ein Konstruktor ohne Namen. Er besteht in einer Klassendeklaration nur aus einem Paar geschweifter Klammern und gleicht einem statischen Initialisierungsblock ohne das Schlüsselwort static:

class Klasse 
{ 
  { 
     // Exemplarinitialisierer. 
  } 
}

Mit Exemplarinitialisierern Konstruktoren vereinfachen

Die Exemplarinitialisierer können gut dazu verwendet werden, Initialisierungsarbeit bei der Objekterzeugung auszuführen. In den Blöcken lässt sich Programmcode setzen, der sonst in jeden Konstruktor kopiert oder andernfalls in einer gesonderten Methode zentralisiert werden müsste. Mit dem Exemplarinitialisierer lässt sich der Programmcode vereinfachen, denn der gemeinsame Teil kann in diesen Block gelegt werden, und wir haben Quellcode-Duplizierung im Quellcode vermieden. Allerdings hat die Technik gegenüber einer langweiligen Initialisierungsmethode auch Nachteile:

  • Zwar ist im Quellcode die Duplizierung nicht mehr vorhanden, aber in der Klassendatei steht sie wieder. Das liegt daran, dass der Compiler alle Anweisungen des Exemplarinitialisierers in jeden Konstruktor kopiert.
  • Exemplarinitialisierer können schnell übersehen werden. Ein Blick auf den Konstruktor verrät uns dann nicht mehr, was er alles macht, da verstreute Exemplarinitialisierer Initialisierungen ändern oder hinzufügen können. Die Initialisierung trägt damit nicht zur Übersichtlichkeit bei.
  • Ein weiteres Manko ist, dass die Initialisierung nur bei neuen Objekten, also mit new(), durchgeführt wird. Wenn Objekte wiederverwendet werden sollen, ist eine private Methode wie initialize(), die das Objekt wie frisch erzeugt initialisiert, gar nicht so schlecht. Eine Methode lässt sich immer aufrufen, und damit sind die Objektzustände wie neu.
  • Die API-Dokumentation führt Exemplarinitialisierer nicht auf; die Konstruktoren müssen also die Aufgabe erklären.

Mehrere Exemplarinitialisierer

In einer Klasse können mehrere Exemplarinitialisierer auftauchen. Sie werden der Reihe nach durchlaufen, und zwar vor dem eigentlichen Konstruktor. Der Grund liegt in der Realisierung der Umsetzung: Der Programmcode der Exemplarinitialisierer wird an den Anfang aller Konstruktoren gesetzt. Objektvariablen wurden schon initialisiert. Ein Programmcode wie der folgende ...

Listing 6.39 WhoIsAustin.java

class WhoIsAustin 
{ 
  String austinPowers = "Mike Myers"; 
 
  { 
    System.out.println( "1 " + austinPowers ); 
  } 
 
  WhoIsAustin() 
  { 
    System.out.println( "2 " + austinPowers ); 
  } 
}

... wird vom Compiler also umgebaut zu:

class WhoIsAustin 
{ 
  String austinPowers; 
 
  WhoIsAustin() 
  { 
    austinPowers = "Mike Myers"; 
    System.out.println( "1 " + austinPowers ); 
    System.out.println( "2 " + austinPowers ); 
  } 
}

Wichtig ist abschließend zu sagen, dass vor dem Zugriff auf eine Objektvariable im Exemplarinitialisierer diese auch deklariert sein muss. So führt Folgendes zu einem Fehler:

class WhoIsDrEvil 
{ 
  { 
    System.out.println( drEvil );      // Ein Compilerfehler 
  } 
 
  String drEvil = "Mike Myers"; 
}

Galileo Computing - Zum Seitenanfang

6.6.5 Finale Werte im Konstruktor und in statischen Blöcken setzen topZur vorigen Überschrift

Wie die Beispiele im vorangegangenen Abschnitt zeigen, werden Objektvariablen erst im Konstruktor gesetzt und statische Variablen in einem static-Block. Diese Tatsache müssen wir jetzt mit finalen Variablen zusammenbringen, was uns dazu bringt, dass auch sie in Konstruktoren beziehungsweise in Initialisierungsblöcken zugewiesen werden. Im Unterschied zu nicht-finalen Variablen müssen finale Variablen auf jeden Fall gesetzt werden, und nur genau ein Schreibzugriff ist möglich.

Finale Werte aus dem Konstruktor belegen

Eine finale Variable darf nur einmal belegt werden. Das bedeutet nicht zwingend, dass sie am Deklarationsort mit einem Wert belegt werden muss, sondern es ist möglich, das auch später vorzunehmen. Der Konstruktor darf zum Beispiel finale Objektvariablen beschreiben. Das Paar finale Variable und initialisierender Konstruktor ist ein häufig genutztes Idiom, wenn Variablenwerte später nicht mehr geändert werden sollen. So ist im Folgenden die Variable pattern final, da sie nur einmalig über den Konstruktor gesetzt und anschließend nur noch gelesen wird.

Listing 6.40 Pattern.java

public class Pattern 
{ 
  private final String pattern; 
 
  public Pattern( String pattern ) 
  { 
    this.pattern = pattern; 
  } 
 
  public String getPattern() 
  { 
    return pattern; 
  } 
}

Java-Stil Immer dann, wenn sich bis auf die direkte Initialisierung vor Ort oder im Konstruktor die Belegung nicht mehr ändert, sollten Entwickler finale Variablen verwenden.


Konstante mit Dateiinhalt initialisieren

Mit diesem Vorgehen lassen sich auch »variable« Konstanten angeben, deren Belegung sich erst zur Laufzeit ergibt. Im nächsten Beispiel soll eine Datei eine Konstante enthalten: die Hubble-Konstante [http://de.wikipedia.org/wiki/Hubble-Konstante] :

Listing 6.41 hubble-constant.txt

77

Die Hubble-Konstante bestimmt die Expansionsgeschwindigkeit des Universums und ist eine zentrale Größe in der Kosmologie. Dummerweise ist die genaue Bestimmung schwer und der Name Konstante eigentlich unpassend. Damit eine Änderung des Wertes nicht zur Neuübersetzung des Java-Programms führen muss, legen wir den Wert in eine Datei und belegen gerade nicht direkt die finale statische Konstantenvariable. Die Klasse liest in einem static-Block den Wert aus der Datei und belegt die finale statische Konstante.

Listing 6.42 LateConstant.java

public class LateConstant 
{ 
  public final static int     HUBBLE; 
  public final        String  ISBN; 
 
  static 
  { 
    HUBBLE = new java.util.Scanner( 
      LateConstant.class.getResourceAsStream("hubble-constant.txt")).nextInt(); 
  } 
 
  public LateConstant() 
  { 
    ISBN = "3572100100"; 
  } 
 
  public static void main( String[] args ) 
  { 
    System.out.println( HUBBLE );                      // 77 
 
    System.out.println( new LateConstant().ISBN );     // 3572100100 
  } 
}

Die Methode getResourceAsStream() liefert einen Datenstrom zum Dateiinhalt, den die Klasse Scanner als Eingabequelle zum Lesen nutzt. Die Objektmethode nextInt() liest anschließend eine Ganzzahl aus der Datei.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Tipp
Zum Katalog: Coding for Fun





 Coding for Fun


 Buchempfehlungen
Zum Katalog: Objektorientierte Programmierung





 Objektorientierte
 Programmierung


Zum Katalog: Einstieg in Eclipse 3.4






 Einstieg in
 Eclipse 3.4


Zum Katalog: Java 6 lernen mit Eclipse






 Java 6 lernen
 mit Eclipse


Zum Katalog: NetBeans Platform 6






 NetBeans
 Platform 6


Zum Katalog: Java und XML






 Java und XML


Zum Katalog: Visual C# 2008






 Visual C# 2008


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Katalog: C++ von A bis Z






 C++ von A bis Z


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2009
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, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de