Einführung in die Importdeklarationen in Java, das Schlüsselwort »import«. [] (Java import, Java-Importdeklaration), Lektion, Seite 722219
https://www.purl.org/stefan_ram/pub/java_importdeklaration (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
Java-Kurs

Importdeklarationen in Java 

Typimportdeklarationen

Damit der maximal explizierte Name eines Eintrags nicht immer ausgeschrieben werden muß, gibt es in Java  die Möglichkeit, einfache Typnamen aus Paketen in eine Übersetzungseinheit einzuführen (zu „importieren“).

Die Bekanntgabe eines Namens für einen Bereich des Quelltextes wird beim Programmieren auch als Deklaration  des Namens bezeichnet, so daß die Importdeklaration ihren Namen zu Recht trägt: Sie deklariert  einen Namen für den Bereich der sie enthaltenden Quelldatei.

Importdeklarationen müssen (JLS7 7.3) am Anfang  der Quelldatei stehen. Eine Importdeklaration beginnt mit dem Schlüsselwort »import«, ihm folgt ein vollständig qualifizierter Name und ein Semikolon. Dadurch wird dann der eigentliche Name (der einfache Name am Ende) des vollständig qualifizierten Namens als Abkürzung  für den vollständig qualifizierten Namen deklariert.

Die folgende Importdeklaration deklariert beispielsweise den Typnamen »Integer« für die Verwendung in der Übersetzungseinheit »Main.java«. Statt »java.lang.Integer« braucht dann nach der Importdeklaration nur noch »Integer« geschrieben werden. Die Importdeklaration definiert »Integer« also als Abkürzung für »java.lang.Integer«.

Main.java
import java.lang.Integer;
import java.lang.Double; public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( Integer.MAX_VALUE );
java.lang.System.out.println( Double.MAX_VALUE ); }}
java.lang.System.out
2147483647
1.7976931348623157E308

⚠ Eine Importdeklaration ist niemals nötig, um eine Klasse zu verwenden. Sie stellt nur eine Möglichkeit zur Abkürzung  folgender Programmteile dar. Insbesondere falsch ist die wiederholt gehörte Vorstellung, daß mit »import« „Bibliotheken importiert“ werden.

Syntax der Typimportdeklaration

Typimportdeklaration (Syntaxdiagramm) ::=
       .------.       .---------.       .-.
----->( import )----->| Typname |----->( ; )----->
'------' '---------' '-'

»import« ist ein Schlüsselwort.

Das Semikolon am Ende der Importdeklaration ist eine lexikalische Einheit.

Bedarfsimportdeklarationen

Falls alle  Typen aus einem Paket mit ihren einfachen Namen erreichbar sein sollen, so kann anstelle eines einfachen Typnamens in der Importdeklaration ein Stern »*« geschrieben werden.

Main.java
import java.lang.*;

public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( Integer.MAX_VALUE );
java.lang.System.out.println( Double.MAX_VALUE ); }}
java.lang.System.out
2147483647
1.7976931348623157E308

Mit einer Bedarfsimportdeklaration wie »import java.lang.*;« wird dem Compiler erlaubt, die Typen des angegebenen Pakets nach Bedarf  zu importieren. Dies bedeutet, daß der Name nur dann  importiert wird, wenn es noch keinen passenden Namen im aktuellen Gültigkeitsbereich gibt. Beispielsweise würde in »new Main()« innerhalb einer Deklaration der Klasse »Main« der Name »Main« für die gerade deklarierte Klasse »Main« stehen. Daher wird dann nicht  versucht, den Typnamen »Main« zu importieren. Würde man statt dessen eine Typimportdeklaration »import java.lang.Main;« schreiben, so würde dies zu einer Fehlermeldung führen, da es eine Klasse »java.lang.Main« nicht gibt. Wenn es aber eine Klasse »java.lang.Main« geben würde, würde »Main« dann für diese Klasse stehen und könnte danach nicht  mehr mit »class Main« deklariert werden. Bei Verwendung von »new Integer()« nach der oben angegebenen Bedarfsimportdeklaration wird »Integer« in der Regel nicht im aktuellen Gültigkeitsbereich gefunden und daher dann importiert.

Wir unterscheiden nun also zwischen einer Typimportdeklaration  ohne Stern (JLS7:7.5.1:“single-type-import declaration”) und einer Bedarfsimportdeklaration  mit einem Stern (JLS7:7.5.2:“type-import-on-demand declaration”).

Syntax der Bedarfsimportdeklaration

Bedarfsimportdeklaration (Syntaxdiagramm, Syntax vereinfacht) ::=
       .------.       .-----------.       .-.        .-.        .-.
----->( import )----->| Paketname |----->( . )----->( * )----->( ; )----->
'------' '-----------' '-' '-' '-'

Es ist nicht  möglich, etwa durch »import java.*;«, mehrere Pakete  mit einem Stern »*« zu importieren, die alle mit »java.« beginnen. Der Stern »*« kann nur für Typen  stehen, nicht für Pakete oder Teile von Paketnamen.

Mehrfache Bedarfsimportdeklarationen

Bedarfsimportdeklarationen können allerdings die Lesbarkeit von Quelltext vermindern, weil es bei ihrer Verwendung nicht mehr an den Importdeklarationszeilen erkennbar ist, welcher Typ zu welchem Paket gehört. Das folgende Programm zeigt Bedarfsimportdeklarationen für Typen aus zwei  Paketen. Ein Leser kann nun dem Quelltext nicht mehr entnehmen, aus welchem Paket die einzelnen Typen (»String« oder »Integer«) stammen.

Main.java
import java.lang.*;
import java.util.*; public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( Integer.MAX_VALUE ); }}
java.lang.System.out
2147483647

Mehrdeutigkeiten bei Bedarfsimportdeklarationen

Falls die Typen mehrerer Pakete mit Bedarfsimportdeklarationen importiert wurden, ist der einfache Name eines Typs nicht mehr eindeutig, falls er in mehreren dieser Pakete vorkommt. Dann muß der Paketname weiterhin verwendet werden, um sich auf einen Typ in einem bestimmten Paket zu beziehen. (Einen Typ »List« gibt es beispielsweise sowohl in dem Paket »java.awt« als auch in dem Paket »java.util«.) Selbst nachdem die Importdeklaration »import java.awt.*« und die Importdeklaration »import java.util.*« verwendet wurde, muß also weiterhin der vollständig qualifizierte Name »java.awt.List« oder der vollständig qualifizierte Name »java.util.List« verwendet werden, um sich eindeutig auf einen dieser beiden Typen zu beziehen, da der Bezeichner »List« alleine dann nicht eindeutig wäre.

Main.java
import java.awt.*;

public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( new List() ); }}
java.lang.System.out
java.awt.List[list0,0,0,0x0,invalid,selected=null]
Main.java
import java.util.*;
import java.awt.*; public final class Main
{ public static void main( final java.lang.String[] args )
{ final List list = null; }}
Konsole
Main.java:5: error: reference to List is ambiguous
{ final List list = null; }}
^
both class java.awt.List in java.awt and interface java.util.List in java.util match
1 error

Selbst wenn ein Typname eindeutig ist, weil er nur in einem der verwendeten Pakete vorkommt, kann es passieren, daß sich dies in einer späteren Version der Programmiersprache ändert, weil die Pakete erweitert wurden. Dann könnte es sein, daß ein Programm plötzlich nicht mehr übersetzt werden kann und überarbeitet werden muß, wenn es solche Bedarfsimportdeklarationen verwendet. Die Verwendbarkeit des Quelltextes ist dadurch als potentiell eingeschränkt.

Ein Autor kennt auch nicht immer alle Namen eines importierten Namensraums, so daß es durch den Import von Namen, derer sich der Programmierer nicht bewußt ist, zu Problemen kommen kann.

Wenn kein Bedarf an einem Import besteht, wird bei einem Bedarfsimports nicht importiert. Wenn also schon eine Klasse »String« bekannt ist, dann wird »java.lang.String« nach »import java.lang.*;« nicht  importiert. Dies kann bedeuten, daß ein Programm unbemerkt sein Verhalten ändern könnte oder zu Fehlermeldungen führen könnte, wenn (versehentlich) eine andere Klasse »String« zugänglich gemacht wurde. Bei Verwendung einer Typimportdeklaration ohne Stern wäre dies aber nicht der Fall, da nach »import java.lang.String;« der einfache Name »String« immer »java.lang.String« bedeutet. Nach einer Bedarfsimportdeklaration ist es ohne weitere Nachforschungen also nicht ersichtlich, auf welche Klasse sich ein einfacher Klassenname bezieht und das Hinzufügen einer weiteren Klasse kann die Bedeutung oder Verwendbarkeit einer Quelldatei verändern.

Da Bedarfsimportdeklarationen zu den beschriebenen Problemen mit der Lesbarkeit, der Verwendbarkeit und der Interpretation von Quelltext führen können, sollten sie in Programmen, die wartbar sein sollen, vermieden werden.

Kombinierte Importdeklarationen

Das folgende Programmbeispiel zeigt, wie mit einer Typimportdeklaration klargestellt wird, welche Bedeutung der unqualifizierte Bezeichner »List« haben soll. Da der Name »List« aus »java.util.List« mit der Typimportdeklaration »import java.util.List;« auf jeden Fall importiert wird, werden die Bedarfsimportdeklarationen zur Auflösung dieses Namens nicht herangezogen.

In demselben Programm könnte dann auch noch »java.awt.List« als voll qualifizierter Name verwendet werden. Obwohl es so möglich ist, Mehrdeutigkeiten aufzulösen, wird von der Verwendung von Bedarfsimportdeklarationen für große Programme, die lange wartbar sein sollen, doch weiterhin abgeraten.

Main.java
import java.util.*;
import java.awt.*;
import java.awt.List; public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( new List() ); }}
java.lang.System.out
java.awt.List[list0,0,0,0x0,invalid,selected=null]

Vorgegebene Importe

Weiter oben wurden die Typen des Pakets »java.lang« durch eine Bedarfsimportdeklaration mit einem Stern zum Bedarfsimport bereitgestellt. Speziell diese Importdeklaration »import java.lang.*« ist aber als niemals nötig, weil sie stets bereits vorgegeben ist. Daher kann diese Übersetzungseinheit auch kürzer geschrieben werden.

Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( Integer.MAX_VALUE ); }}
java.lang.System.out
2147483647

Da es sich bei diesem vorgegebenen Import um einen Bedarfsimport  handelt, besteht allerdings das schon angesprochene Problem mit der Mehrdeutigkeit der Bedeutung eines einfachen Namens: Der einfache Name »String« muß nicht »java.lang.String« bedeuten; er kann sich auch auf eine andere Klasse mit dem eigentlichen Namen »String« beziehen; welche Klasse dies ist kann außerhalb des Programms festgelegt werden; dies gefährdet die Sicherheit, Eindeutigkeit und Funktionsfähigkeit eines Programms. Wenn ein sicherer Bezug auf »java.lang.String« hergestellt werden soll, ist entweder eine Typimportdeklaration »import java.lang.String;« ohne Stern zu verwenden oder der maximal qualifizierte Klassenname »java.lang.String«.

Vorteile von Typimportdeklarationen

Durch die Auflistung von Typimportdeklarationen am Anfang eines Programms wird schnell erkennbar, welche Typen ein Programm benötigt.

Es ist möglich, Typnamen durch eine einzige Änderung an einer Stelle (nämlich der Typimportdeklaration) aus einem anderen Paket zu importieren.

Nachteile von Typimportdeklarationen

Beim Übersetzen eines Programms wird im allgemeinen nicht geprüft, ob die angegebenen Typen auch wirklich benötigt werden, so daß die Auflistung von Typimportdeklaration am Anfang eines Quelltextes über die tatsächlich verwendeten Typen täuschen könnte. Wenn ein Name aus einem Programm entfernt wird, aber vergessen wird, die zugehörige Importdeklaration zu entfernen, dann enthält die Auflistung der Typimportdeklarationen unnötige Bestandteile.

Eine durchgehende Verwendung maximal qualifizierter Namen erlaubt es dem Leser eines Programmstücks, sofort zu erkennen, zu welchem Paket ein Typ gehört, ohne daß erst oben in einer Liste von Importdeklarationen nachgesehen werden muß. Wenn Teile des Quelltextes, der Typimportdeklarationen verwendet, herauskopiert werden, sind diese Teile ohne die Typimportdeklarationen nicht immer verständlich (es ist nicht immer klar, welche Typen gemeint sind).

Programmstücke mit voll qualifizierten Namen können auf einfache Weise zwischen verschiedenen Quelldateien ausgetauscht werden, ohne daß sie ihre Bedeutung möglicherweise ändern, weil in der anderen Quelldatei andere Importdeklarationen stehen, beziehungsweise, ohne daß es nötig wird dann auch noch die zugehörigen Importdeklarationen zu finden und ebenfalls zu kopieren.

Statische Importe

Auch statische Einträge (wie statische Methoden) einer Klasse können importiert werden.

Das folgende Programmbeispiel zeigt den Import der Methode "random" der Klasse "java.lang.Math". Danach kann im Quelltext dann einfach "random" verwendet werden, um diese Methode anzugeben. Es wird damit auch möglich, den Eintrag "out" der Klasse "java.lang.System" einfach nur mit "out" zu bezeichnen. Für solche einen „statischen Import“ muß dem Schlüsselwort "import" noch das Schlüsselwort "static" direkt folgen.

StaticImport.java
import static java.lang.Math.random;
import static java.lang.System.out; public class StaticImport
{ public static void main( String[] args )
{ out.println( random() ); }}

Durch die Verwendung eines Sternchens können auch alle  Einträge einer Klasse importiert werden.

StaticImportAll.java
import static java.lang.Math.*;
import static java.lang.System.*; public class StaticImportAll
{ public static void main( String[] args )
{ out.println( random() ); }}

Die Verwendung der Sternchen führt aber wieder zu dem Problem der Verschlechterung der Lesbarkeit, da der Name "out" und der Name "random" nun nicht mehr durch Lesen des Quelltextes einer Klasse zugeordnet werden können. Daher sollten die Sternchen vermieden werden.

Übungsaufgaben

/   Programm beurteilen

Sagen Sie, ohne das Programm übersetzen zu lassen, voraus, ob beim Versuch. das folgende Programm zu übersetzen, eine Fehlermeldung ausgegeben werden wird.

Main.java
import java.util.List;

public final class Main
{ public static void main( final java.lang.String[] args )
{ new java.awt.List(); }}

/   Namen finden

Ermitteln Sie, ohne das Programm zu starten, den vollständig qualifizierten Namen der in dem folgenden Programm verwendeten Klasse »Adler32«.

Main.java
import java.rmi.activation.*;
import java.nio.file.attribute.*;
import java.util.zip.*; public final class Main
{ public static void main( final java.lang.String[] args )
{ new Adler32(); }}

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722219 stefan_ram:722219 Java import, Java-Importdeklaration Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722219, slrprddef722219, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/java_importdeklaration