Rheinwerk Computing < openbook >


 
Inhaltsverzeichnis
Materialien
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Arrays und ihre Anwendungen
5 Der Umgang mit Zeichenketten
6 Eigene Klassen schreiben
7 Objektorientierte Beziehungsfragen
8 Ausnahmen müssen sein
9 Geschachtelte Typen
10 Besondere Typen der Java SE
11 Generics<T>
12 Lambda-Ausdrücke und funktionale Programmierung
13 Architektur, Design und angewandte Objektorientierung
14 Java Platform Module System
15 Die Klassenbibliothek
16 Einführung in die nebenläufige Programmierung
17 Einführung in Datenstrukturen und Algorithmen
18 Einführung in grafische Oberflächen
19 Einführung in Dateien und Datenströme
20 Einführung ins Datenbankmanagement mit JDBC
21 Bits und Bytes, Mathematisches und Geld
22 Testen mit JUnit
23 Die Werkzeuge des JDK
A Java SE-Module und Paketübersicht
Stichwortverzeichnis


Download:

- Listings, ca. 2,7 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 3 Klassen und Objekte
Pfeil 3.1 Objektorientierte Programmierung (OOP)
Pfeil 3.1.1 Warum überhaupt OOP?
Pfeil 3.1.2 Denk ich an Java, denk ich an Wiederverwendbarkeit
Pfeil 3.2 Eigenschaften einer Klasse
Pfeil 3.2.1 Klassenarbeit mit Point
Pfeil 3.3 Natürlich modellieren mit der UML (Unified Modeling Language) *
Pfeil 3.3.1 Hintergrund und Geschichte der UML *
Pfeil 3.3.2 Wichtige Diagrammtypen der UML *
Pfeil 3.3.3 UML-Werkzeuge *
Pfeil 3.4 Neue Objekte erzeugen
Pfeil 3.4.1 Ein Exemplar einer Klasse mit dem Schlüsselwort new anlegen
Pfeil 3.4.2 Deklarieren von Referenzvariablen
Pfeil 3.4.3 Jetzt mach mal ’nen Punkt: Zugriff auf Objektattribute und -methoden
Pfeil 3.4.4 Der Zusammenhang von new, Heap und Garbage-Collector
Pfeil 3.4.5 Überblick über Point-Methoden
Pfeil 3.4.6 Konstruktoren nutzen
Pfeil 3.5 ZZZZZnake
Pfeil 3.6 Pakete schnüren, Importe und Compilationseinheiten
Pfeil 3.6.1 Java-Pakete
Pfeil 3.6.2 Pakete der Standardbibliothek
Pfeil 3.6.3 Volle Qualifizierung und import-Deklaration
Pfeil 3.6.4 Mit import p1.p2.* alle Typen eines Pakets erreichen
Pfeil 3.6.5 Hierarchische Strukturen über Pakete und die Spiegelung im Dateisystem
Pfeil 3.6.6 Die package-Deklaration
Pfeil 3.6.7 Unbenanntes Paket (default package)
Pfeil 3.6.8 Compilationseinheit (Compilation Unit)
Pfeil 3.6.9 Statischer Import *
Pfeil 3.7 Mit Referenzen arbeiten, Vielfalt, Identität, Gleichwertigkeit
Pfeil 3.7.1 null-Referenz und die Frage der Philosophie
Pfeil 3.7.2 Alles auf null? Referenzen testen
Pfeil 3.7.3 Zuweisungen bei Referenzen
Pfeil 3.7.4 Methoden mit Referenztypen als Parametern
Pfeil 3.7.5 Identität von Objekten
Pfeil 3.7.6 Gleichwertigkeit und die Methode equals(…)
Pfeil 3.8 Zum Weiterlesen
 

Zum Seitenanfang

3.6    Pakete schnüren, Importe und Compilationseinheiten Zur vorigen ÜberschriftZur nächsten Überschrift

Die Klassenbibliothek von Java ist mit Tausenden Typen sehr umfangreich und deckt alles ab, was Entwickler von plattformunabhängigen Programmen als Basis benötigen. Dazu gehören Datenstrukturen, Klassen zur Datums-/Zeitberechnung, Dateiverarbeitung usw. Die meisten Typen sind in Java selbst implementiert (und der Quellcode ist in der Regel aus der Entwicklungsumgebung direkt verfügbar), aber einige Teile sind nativ implementiert, etwa wenn es darum geht, aus einer Datei zu lesen.

Wenn wir eigene Klassen programmieren, ergänzen sie sozusagen die Standardbibliothek; im Endeffekt wächst damit die Anzahl der möglichen Typen, die ein Programm nutzen kann.

 

Zum Seitenanfang

3.6.1    Java-Pakete Zur vorigen ÜberschriftZur nächsten Überschrift

Ein Paket ist eine Gruppe thematisch zusammengehöriger Typen. Pakete lassen sich in Hierarchien ordnen, sodass ein Paket wieder ein anderes Paket enthalten kann; das ist genauso wie bei der Verzeichnisstruktur des Dateisystems. Beispiele für Pakete sind:

  • java.awt

  • java.util

  • com.google

  • org.apache.commons.math3.fraction

  • com.tutego.insel

Die Klassen der Java-Standardbibliothek befinden sich in Paketen, die mit java und javax beginnen. Google nutzt die Wurzel com.google; die Apache Foundation veröffentlicht Java-Code unter org.apache. So können wir von außen ablesen, von welchen Typen die eigene Klasse abhängig ist.

 

Zum Seitenanfang

3.6.2    Pakete der Standardbibliothek Zur vorigen ÜberschriftZur nächsten Überschrift

Die logische Gruppierung und Hierarchie lässt sich sehr gut an der Java-Bibliothek beobachten. Die Java-Standardbibliothek beginnt mit der Wurzel java, einige Typen liegen in javax. Unter diesem Paket liegen weitere Pakete, etwa awt, math und util. In java.math liegen zum Beispiel die Klassen BigInteger und BigDecimal, denn die Arbeit mit beliebig großen Ganz- und Fließkommazahlen gehört eben zum Mathematischen. Ein Punkt und ein Polygon, repräsentiert durch die Klassen Point und Polygon, gehören in das Paket für grafische Oberflächen, und das ist das Paket java.awt.

Wenn jemand eigene Klassen in Pakete mit dem Präfix java setzen würde, etwa java.tutego, würde ein Programmautor damit Verwirrung stiften, da nicht mehr nachvollziehbar ist, ob das Paket Bestandteil jeder Distribution ist. Daher ist dieses Präfix für eigene Pakete verboten.

Klassen, die in einem Paket liegen, das mit javax beginnt, können Teil der Java SE sein wie javax.swing, müssen aber nicht zwingend zur Java SE gehören; dazu folgt mehr in Abschnitt 15.1.2, »Übersicht über die Pakete der Standardbibliothek«.

 

Zum Seitenanfang

3.6.3    Volle Qualifizierung und import-Deklaration Zur vorigen ÜberschriftZur nächsten Überschrift

Um die Klasse Point, die im Paket java.awt liegt, außerhalb des Pakets java.awt zu nutzen – und das ist für uns Nutzer immer der Fall –, muss sie dem Compiler mit der gesamten Paketangabe bekannt gemacht werden. Hierzu reicht der Klassenname allein nicht aus, denn es kann ja sein, dass der Klassenname mehrdeutig ist und eine Klassendeklaration in unterschiedlichen Paketen existiert.

Typen sind erst durch die Angabe ihres Pakets eindeutig identifiziert. Ein Punkt trennt Pakete, also schreiben wir java.awt und java.util – nicht einfach nur awt oder util. Mit einer weltweit unzähligen Anzahl von Paketen und Klassen wäre sonst eine Eindeutigkeit gar nicht machbar. Es kann in verschiedenen Paketen durchaus ein Typ mit gleichem Namen vorkommen, etwa java.util.List und java.awt.List oder java.util.Date und java.sql.Date. Und org.apache.commons.lang3.tuple hat einen Typ Pair, javafx.util auch. Daher bilden Paket und Typ eine Einheit und das eine ist oder das andere nicht eindeutig.

Um dem Compiler die präzise Zuordnung einer Klasse zu einem Paket zu ermöglichen, gibt es zwei Möglichkeiten: Zum einen lassen sich die Typen voll qualifizieren, wie wir das bisher getan haben. Eine alternative und praktischere Möglichkeit besteht darin, den Compiler mit einer import-Deklaration auf die Typen im Paket aufmerksam zu machen:

Listing 3.6    AwtWithoutImport.java







class AwtWithoutImport {

public static void main(String[] args){

java.awt.Point p =

new java.awt.Point();



java.awt.Polygon t =

new java.awt.Polygon();

t.addPoint( 10, 10 );

t.addPoint( 10, 20 );

t.addPoint( 20, 10 );



System.out.println( p );

System.out.println( t.contains(15, 15) );

}

}

Listing 3.7    AwtWithImport.java

import java.awt.Point;

import java.awt.Polygon;



class AwtWithImport {

public static void main(String[] args){

Point p = new Point();





Polygon t = new Polygon();



t.addPoint( 10, 10 );

t.addPoint( 10, 20 );

t.addPoint( 20, 10 );



System.out.println( p );

System.out.println( t.contains(15, 15) );

}

}

Tabelle 3.3    Typzugriff über volle Qualifikation und mit »import«-Deklaration

Während der Quellcode auf der linken Seite die volle Qualifizierung verwendet und jeder Verweis auf einen Typ mehr Schreibarbeit kostet, ist im rechten Fall beim import nur der Klassenname genannt und die Paketangabe in ein import »ausgelagert«. Alle Typen, die bei import genannt werden, merkt sich der Compiler für diese Datei in einer Datenstruktur. Kommt der Compiler zur Zeile mit Point p = new Point();, findet er den Typ Point in seiner Datenstruktur und kann den Typ dem Paket java.awt zuordnen. Damit ist wieder die unabkömmliche Qualifizierung gegeben.

[»]  Hinweis

Die Typen aus java.lang sind automatisch importiert, sodass z. B. ein import java.lang. String; nicht nötig ist.

[+]  Tipp

Import-Deklarationen sind der übliche Weg, um Schreibarbeit zu sparen. Eine Ausnahme bilden gleichlautende Typen in unterschiedlichen Paketen. So gibt es in den Paketen java.awt und java.util den Typ List. Ein einfaches import java.awt.* und java.util.* hilft da nicht, weil der Compiler nicht weiß, ob die GUI-Komponente oder die Datenstruktur gemeint ist. Eine volle Qualifizierung löst das Problem.

 

Zum Seitenanfang

3.6.4    Mit import p1.p2.* alle Typen eines Pakets erreichen Zur vorigen ÜberschriftZur nächsten Überschrift

Greift eine Java-Klasse auf mehrere andere Typen des gleichen Pakets zurück, kann die Anzahl der import-Deklarationen groß werden. In unserem Beispiel nutzen wir mit Point und Polygon nur zwei Klassen aus java.awt, aber es lässt sich schnell ausmalen, was passiert, wenn aus dem Paket für grafische Oberflächen zusätzlich Fenster, Beschriftungen, Schaltflächen, Schieberegler usw. eingebunden werden. In diesem Fall darf ein * als letztes Glied in einer import-Deklaration stehen:

import java.awt.*;

import java.math.*;

Mit dieser Syntax kennt der Compiler alle Typen im Paket java.awt und java.math, sodass die Klassen Point und Polygon genau bekannt sind, wie auch die Klasse BigInteger.

[»]  Hinweis

Das * ist nur auf der letzten Hierarchieebene erlaubt und gilt immer für alle Typen in diesem Paket. Syntaktisch falsch sind:

import *;            // inline image Syntax error on token "*", Identifier expected

import java.awt.Po*; // inline image Syntax error on token "*", delete this token

Eine Anweisung wie import java.*; ist zwar syntaktisch korrekt, aber dennoch ohne Wirkung, denn direkt im Paket java gibt es keine Typdeklarationen, sondern nur Unterpakete.

Die import-Deklaration bezieht sich nur auf ein Verzeichnis (in der Annahme, dass die Pakete auf das Dateisystem abgebildet werden) und schließt die Unterverzeichnisse nicht ein.

Das * verkürzt zwar die Anzahl der individuellen import-Deklarationen, es ist aber gut, zwei Dinge im Kopf zu behalten:

  • Falls zwei unterschiedliche Pakete einen gleichlautenden Typ beherbergen, etwa Date in java.util und java.sql, so kommt es bei der Verwendung des Typs zu einem Übersetzungsfehler. Hier muss voll qualifiziert werden.

  • Die Anzahl der import-Deklarationen sagt etwas über den Grad der Komplexität aus. Je mehr import-Deklarationen es gibt, desto größer werden die Abhängigkeiten zu anderen Klassen, was im Allgemeinen ein Alarmzeichen ist. Zwar zeigen grafische Tools die Abhängigkeiten genau an, doch ein import * kann diese erst einmal verstecken.

[+]  Best-Practice

Entwicklungsumgebungen setzen die import-Deklarationen in der Regel automatisch und falten die Blöcke üblicherweise ein. Daher sollte der * nur sparsam eingesetzt werden, denn er »verschmutzt« den Namensraum durch viele Typen und erhöht die Gefahr von Kollisionen.

 

Zum Seitenanfang

3.6.5    Hierarchische Strukturen über Pakete und die Spiegelung im Dateisystem Zur vorigen ÜberschriftZur nächsten Überschrift

Die zu einem Paket gehörenden Klassen befinden sich normalerweise[ 115 ](Ich schreibe »normalerweise«, da die Paketstruktur nicht zwingend auf Verzeichnisse abgebildet werden muss. Pakete könnten beispielsweise vom Klassenlader aus einer Datenbank gelesen werden. Im Folgenden wollen wir aber immer von Verzeichnissen ausgehen. ) im gleichen Verzeichnis. Der Name des Pakets ist gleich dem Namen des Verzeichnisses (und natürlich umgekehrt). Statt des Verzeichnistrenners (etwa »/« oder »\«) steht ein Punkt.

Nehmen wir folgende Verzeichnisstruktur mit einer Hilfsklasse an:

com/tutego/insel/printer/DatePrinter.class

Hier ist der Paketname com.tutego.insel.printer und somit der Verzeichnisname com/tutego/insel/printer. Umlaute und Sonderzeichen sollten vermieden werden, da sie auf dem Dateisystem immer wieder für Ärger sorgen. Aber Bezeichner sollten ja sowieso immer auf Englisch sein.

Der Aufbau von Paketnamen

Prinzipiell kann ein Paketname beliebig sein, doch Hierarchien bestehen in der Regel aus umgedrehten Domänennamen. Aus der Domäne zur Webseite http://tutego.com wird also com.tutego. Diese Namensgebung gewährleistet, dass Klassen auch weltweit eindeutig bleiben. Ein Paketname wird in aller Regel komplett kleingeschrieben.

 

Zum Seitenanfang

3.6.6    Die package-Deklaration Zur vorigen ÜberschriftZur nächsten Überschrift

Um die Klasse DatePrinter in ein Paket com.tutego.insel.printer zu setzen, müssen zwei Dinge gelten:

  • Sie muss sich physikalisch in einem Verzeichnis befinden, also in com/tutego/insel/ printer.

  • Der Quellcode enthält zuoberst eine package-Deklaration.

Die package-Deklaration muss ganz am Anfang stehen, sonst gibt es einen Übersetzungsfehler (selbstverständlich lassen sich Kommentare vor die package-Deklaration setzen):

Listing 3.8    src/main/java/com/tutego/printer/DatePrinter.java

package com.tutego.insel.printer;



import java.time.LocalDate;

import java.time.format.*;



public class DatePrinter {

public static void printCurrentDate() {

DateTimeFormatter fmt = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM );

System.out.println( LocalDate.now().format( fmt ) );

}

}

Hinter die package-Deklaration kommen wie gewohnt import-Deklaration(en) und die Typdeklaration(en).

Um die Klasse zu nutzen, bieten sich wie bekannt zwei Möglichkeiten: einmal über die volle Qualifizierung und einmal über die import-Deklaration. Die erste Variante sieht so aus:

Listing 3.9    src/main/java/DatePrinterUser1.java

public class DatePrinterUser1 {

public static void main( String[] args ) {

com.tutego.insel.printer.DatePrinter.printCurrentDate(); // 20.09.2020

}

}

Und hier ist die Variante mit der import-Deklaration:

Listing 3.10    src/main/java/DatePrinterUser2.java

import com.tutego.insel.printer.DatePrinter;



public class DatePrinterUser2 {

public static void main( String[] args ) {

DatePrinter.printCurrentDate(); // 20.09.2020

}

}
[+]  Tipp

Eine Entwicklungsumgebung nimmt uns viel Arbeit ab, daher bemerken wir die Dateioperationen – wie das Anlegen von Verzeichnissen – in der Regel nicht. Auch das Verschieben von Typen in andere Pakete und die damit verbundenen Änderungen im Dateisystem und die Anpassungen an den import- und package-Deklarationen übernimmt eine moderne IDE für uns.

 

Zum Seitenanfang

3.6.7    Unbenanntes Paket (default package) Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Klasse ohne Paketangabe befindet sich im unbenannten Paket (engl. unnamed package) bzw. Default-Paket. Es ist eine gute Idee, eigene Klassen immer in Paketen zu organisieren. Das erlaubt auch feinere Sichtbarkeiten, und Konflikte mit anderen Unternehmen und Autoren werden vermieden. Es wäre ein großes Problem, wenn a) jedes Unternehmen unübersichtlich alle Klassen in das unbenannte Paket setzen und dann b) versuchen würde, die Bibliotheken auszutauschen: Konflikte wären vorprogrammiert.

Eine im Paket befindliche Klasse kann jede andere sichtbare Klasse aus anderen Paketen importieren, aber keine Klassen aus dem unbenannten Paket. Nehmen wir Sugar im unbenannten Paket und Chocolate im Paket com.tutego an:

Sugar.class

com/tutego/insel/Chocolate.class

Das Verzeichnis »default package« steht in Eclipse für das unbenannte Paket.

Abbildung 3.7    Das Verzeichnis »default package« steht in Eclipse für das unbenannte Paket.

Die Klasse Chocolate kann Sugar nicht nutzen, da Klassen aus dem unbenannten Paket nicht für Unterpakete sichtbar sind. Nur andere Klassen im unbenannten Paket können Klassen im unbenannten Paket nutzen.

Stände nun Sugar in einem Paket – das auch ein Oberpaket sein kann! –, so wäre das wiederum möglich, und Chocolate könnte Sugar importieren:

com/Sugar.class

com/tutego/insel/Chocolate.class

 

Zum Seitenanfang

3.6.8    Compilationseinheit (Compilation Unit) Zur vorigen ÜberschriftZur nächsten Überschrift

Eine .java-Datei ist eine Compilationseinheit (Compilation Unit), die aus drei (optionalen) Segmenten besteht – in dieser Reihenfolge:

  1. package-Deklaration

  2. import-Deklaration(en)

  3. Typdeklaration(en)

So besteht eine Compilationseinheit aus höchstens einer Paketdeklaration (nicht nötig, wenn der Typ im Default-Paket stehen soll), beliebig vielen import-Deklarationen und beliebig vielen Typdeklarationen. Der Compiler übersetzt jeden Typ einer Compilationseinheit in eine eigene .class-Datei. Ein Paket ist letztendlich eine Sammlung aus Compilationseinheiten. In der Regel ist die Compilationseinheit eine Quellcodedatei; die Codezeilen könnten grundsätzlich auch aus einer Datenbank kommen oder zur Laufzeit generiert werden.

 

Zum Seitenanfang

3.6.9    Statischer Import * Zur vorigen ÜberschriftZur nächsten Überschrift

Die import-Deklaration informiert den Compiler über die Pakete, sodass ein Typ nicht mehr voll qualifiziert werden muss, wenn er im import-Teil explizit aufgeführt wird oder wenn das Paket des Typs über * genannt ist.

Falls eine Klasse statische Methoden oder Konstanten vorschreibt, werden ihre Eigenschaften immer über den Typnamen angesprochen. Java bietet mit dem statischen Import die Möglichkeit, die statischen Methoden oder Variablen ohne vorangestellten Typnamen sofort zu nutzen. Während also das normale import dem Compiler Typen benennt, macht ein statisches import dem Compiler Klasseneigenschaften bekannt, geht also eine Ebene tiefer.

[zB]  Beispiel

Binde für die Bildschirmausgabe die statische Variable out aus System statisch ein:

import static java.lang.System.out;

Bei der sonst üblichen Ausgabe über System.out.printXXX(…) kann nach dem statischen Import der Klassenname entfallen, und es bleibt beim out.printXXX(…).

Binden wir in einem Beispiel mehrere statische Eigenschaften mit einem statischen import ein:

Listing 3.11    src/main/java/com/tutego/insel/oop/StaticImport.java

package com.tutego.insel.oop;



import static java.lang.System.out;

import static javax.swing.JOptionPane.showInputDialog;

import static java.lang.Integer.parseInt;

import static java.lang.Math.max;

import static java.lang.Math.min;



class StaticImport {



public static void main( String[] args ) {

int i = parseInt( showInputDialog( "Erste Zahl" ) );

int j = parseInt( showInputDialog( "Zweite Zahl" ) );

out.printf( "%d ist größer oder gleich %d.%n",

max(i, j), min(i, j) );

}

}

Mehrere Typen statisch importieren

Der statische Import

import static java.lang.Math.max;

import static java.lang.Math.min;

bindet die statische max(…)/min(…)-Methode ein. Besteht Bedarf an weiteren statischen Methoden, gibt es neben der individuellen Aufzählung eine Wildcard-Variante:

import static java.lang.Math.*;
[»]  Best Practice

Auch wenn Java diese Möglichkeit bietet, sollte der Einsatz maßvoll erfolgen. Die Möglichkeit der statischen Importe ist nützlich, wenn Klassen Konstanten nutzen wollen, allerdings besteht auch die Gefahr, dass durch den fehlenden Typnamen nicht mehr sichtbar ist, woher die Eigenschaft eigentlich kommt und welche Abhängigkeit sich damit aufbaut. Auch gibt es Probleme mit gleichlautenden Methoden: Eine Methode aus der eigenen Klasse überdeckt statisch importierte Methoden. Wenn also später in der eigenen Klasse – oder Oberklasse – eine Methode aufgenommen wird, die die gleiche Signatur hat wie eine statisch importierte Methode, wird das zu keinem Compilerfehler führen, sondern die Semantik wird sich ändern, weil jetzt die neue eigene Methode verwendet wird und nicht mehr die statisch importierte.

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java ist auch eine Insel Java ist auch eine Insel

Jetzt Buch bestellen


 Buchempfehlungen
Zum Rheinwerk-Shop: Captain CiaoCiao erobert Java

Captain CiaoCiao erobert Java




Zum Rheinwerk-Shop: Java SE 9 Standard-Bibliothek

Java SE 9 Standard-Bibliothek




Zum Rheinwerk-Shop: Algorithmen in Java

Algorithmen in Java




Zum Rheinwerk-Shop: Objektorientierte Programmierung

Objektorientierte Programmierung




 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2021

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.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de



Cookie-Einstellungen ändern