Alle Tabs der Lerneinheit (Erklärung · Interaktiv verstehen · Praxis-Übung · Klausur-Quiz) als durchgehender Text. Ideal zum Wiederholen vor der Klausur, und für Suchmaschinen wie Google, Bing und KI-Suche (ChatGPT, Perplexity).
Erklärung
Stell dir vor du baust ein größeres Programm. Hunderte Klassen. Manche heißen Util, List, Logger. Wie verhinderst du, dass deine User mit der User aus einer fremden Library kollidiert, ohne ständig den vollen Pfad mitzuschleppen? Pakete sind Javas Antwort: zusammengehörige Klassen werden in Namensräumen gebündelt, organisiert wie Ordner. Und Imports holen dir Klassen aus anderen Paketen herein, sodass du sie kurz beim Namen nennen kannst statt jedes Mal den langen Paket-Pfad davorzuschreiben.
Du lernst hier, wie eine package-Deklaration eine Klasse einem Namensraum zuordnet, wie der voll qualifizierte Name (fully qualified name = Paket plus Klassenname, z. B. java.util.ArrayList) entsteht, wie import, Wildcard-Import und import static funktionieren. Außerdem, warum java.lang automatisch verfügbar ist, was der Source-Root mit der Verzeichnisstruktur zu tun hat, wie classpath/modulepath die Klassen zur Laufzeit findet und welche IDE-Fehlermeldungen typisch sind. Wie genau Sichtbarkeit (public, protected, package-private, private) zwischen Paketen wirkt, schauen wir uns weiter unten in den Abschnitten Sichtbarkeit auf Paket-Ebene und Sichtbarkeits-Übersicht mit Paketen an, das ist der zweite große Klausur-Block dieses Themas.
Klausur-Relevanz: package/import ist in WInf-Prog-1-Klausuren ein typischer Frage-Block. Übliche Formulierungen sind: "Wie sieht der Import-Pfad aus?", "Was ist der Unterschied zwischen package und import?", "Welche package-Zeile gehört in diese Datei?".
Die Idee in einem Satz
Paket (package): Eine Gruppe zusammengehöriger Klassen mit eindeutigem Namensraum, organisiert wie Ordner. Import: Mache Klassen aus anderen Paketen ohne ihren vollen Paket-Pfad (den voll qualifizierten Namen) nutzbar.
Package-Deklaration
package de.unihamburg.studi; // erste Code-Zeile in der Datei!
public class Student {
private String name;
// ...
}
Konvention: Pakete sind kleingeschrieben, durch Punkte getrennt, oft mit umgekehrtem Domain-Namen als Präfix (com.firma.projekt, de.uni.fachbereich). Damit machst du weltweit eindeutige Namen sehr wahrscheinlich, sofern du eine eigene Domain bzw. Organisation als Präfix nutzt. Technisch erzwingt Java das aber nicht.
Sprachregel vs. Projektkonvention
Hier lohnt sich eine präzise Unterscheidung, die in Klausuren oft schwammig dargestellt wird:
- Sprachregel (gilt immer, JLS): Die
package-Zeile bestimmt den voll qualifizierten Namen der Klasse. Auspackage de.unihamburg.studi;plusclass Studentwirdde.unihamburg.studi.Student. Das ist unabhängig davon, in welchem Ordner die Datei physisch liegt. - Projekt- und Tooling-Konvention (Standardfall): In normalen IDE-, Maven- oder Gradle-Projekten muss die Ordnerstruktur relativ zum Source-Root zum Paketnamen passen, sonst findet das Build-Tool die Klasse oft nicht korrekt oder meckert beim Kompilieren. Eclipse, IntelliJ, Maven und Gradle erwarten
de/unihamburg/studi/Student.javaunter dem Source-Root.
Fortgeschrittenes Detail (nicht klausurrelevant): Der nackte
javac-Compiler ist toleranter: Über-sourcepathund-d(Ausgabeordner) kann er Quelldateien auch aus anderen Ordnern übersetzen. Verlass dich darauf aber nie im Projektalltag, halte dich an die Konvention, dann passt alles automatisch.
Kleingedrucktes zur package-Zeile: Falls eine
package-Deklaration vorhanden ist, steht sie vor allenimports und Typdeklarationen, davor höchstens Kommentare/Whitespace oder Package-Annotationen. Eine Datei ganz ohnepackage-Zeile liegt im Default-Package (in echten Projekten unüblich).
Standard-Verzeichnisstruktur (so erwartet es deine IDE):
src/ ← Source-Root (zählt NICHT zum Paketnamen)
└── de/
└── unihamburg/
└── studi/
└── Student.java ← package de.unihamburg.studi;
Lies die Baumstruktur von oben nach unten: Jeder Ordner unter dem Source-Root src/ ist ein Stück des Paketnamens. Der Source-Root selbst (src/) gehört nicht dazu, deshalb heißt das Paket de.unihamburg.studi und nicht src.de.unihamburg.studi. Weiter unten im Abschnitt Interaktiv verstehen kannst du mit dem Paket-Baum-Visualizer genau dieses Zusammenspiel aus package-Zeile, Dateipfad und Import live durchklicken.
Import: Klassen nutzen
Ohne Import musst du den voll qualifizierten Namen (fully qualified name, also Paket plus Klassenname) schreiben:
java.util.ArrayList<String> liste = new java.util.ArrayList<>();
Mit Import wird das kurz:
import java.util.ArrayList;
ArrayList<String> liste = new ArrayList<>();
Import-Varianten:
import java.util.ArrayList; // Einzelimport
import java.util.*; // Alles aus java.util (Wildcard)
import static java.lang.Math.PI; // Statische Member direkt nutzbar
Nach import static java.lang.Math.PI kannst du PI statt Math.PI schreiben, nützlich, aber es kann unklar werden, wenn du nicht weißt, woher das Symbol kommt.
classpath und modulepath: wie Java die Klassen findet
Der import löst nur den kurzen Namen auf, er sagt nichts darüber, wo die .class-Dateien physisch liegen. Das übernimmt der classpath (klassisch) bzw. der modulepath (ab dem Java-Modulsystem, Java 9+).
- classpath: eine Liste von Verzeichnissen und JAR-Dateien, in denen der Compiler und die JVM nach kompilierten Klassen suchen. Setzbar über
-classpath/-cpoder die UmgebungsvariableCLASSPATH. Findet die JVM die Klasse zur Laufzeit nicht, fliegt eineNoClassDefFoundErroroderClassNotFoundException, obwohl der Code sauber kompiliert hat. Faustregel: Bei normal referenzierten Klassen siehst du meist einenNoClassDefFoundError; eineClassNotFoundExceptionkommt typischerweise beim expliziten Laden überClass.forName(...)oderClassLoader.loadClass(...). - modulepath: das modernere Pendant, wenn dein Projekt eine
module-info.javamitrequires/exportshat. Im Studium reicht in der Regel das classpath-Modell, das Modulsystem ist meist nur ein Randthema.
Merke: import ist reine Kompilierzeit-Bequemlichkeit (kurzer Name statt voll qualifiziert), classpath/modulepath ist die Laufzeit-Suchstrategie für die Bytecode-Dateien. Beides hat nichts miteinander zu tun, ein fehlender Import ist ein anderes Problem als eine Klasse, die nicht im classpath liegt.
java.lang ist auto-importiert
Klassen aus java.lang (String, System, Math, Integer, Object ...) sind automatisch importiert (laut Sprachregel immer verfügbar; in modernen Java-Versionen stammen sie aus dem Standardmodul java.base). Du musst sie NIE explizit importieren. Deshalb funktioniert System.out.println ohne import.
Typische IDE-Fehler
Diese Meldungen siehst du in Eclipse oder IntelliJ am häufigsten, und sie sind fast immer Paket-/Import-bezogen:
- "The declared package X does not match the expected package Y" (Eclipse): Deine
package-Zeile und der Ordnerpfad unter dem Source-Root passen nicht zusammen. Datei verschieben oder package-Zeile anpassen. - "cannot find symbol" / "Cannot resolve symbol 'ArrayList'": Der Import fehlt oder ist falsch geschrieben. IDE-Quickfix (
Alt+Enterin IntelliJ,Strg+Shift+Oin Eclipse) ergänzt ihn automatisch. - "package X does not exist": Das Paket ist nicht im classpath, oft eine fehlende Bibliothek/Dependency oder ein Tippfehler im Paketnamen.
Sichtbarkeit auf Paket-Ebene
Erinnerung aus dem Sichtbarkeits-Topic: ohne Modifier ist eine Klasse / ein Feld / eine Methode package-private, nur im selben Paket zugreifbar.
package de.unihamburg.studi;
class InternalHelper { // package-private!
void log(String msg) { /* ... */ }
}
Diese Klasse ist NICHT von außerhalb de.unihamburg.studi zugreifbar. Praktisch für interne Helper-Klassen, die nicht Teil der öffentlichen API sein sollen.
Namens-Konflikte lösen
Du hast zwei Klassen mit gleichem Namen aus unterschiedlichen Paketen:
import java.util.Date;
// import java.sql.Date; // Geht NICHT, Konflikt mit oberer Zeile
java.util.Date heute = new java.util.Date();
java.sql.Date dbDatum = new java.sql.Date(0);
Lösung: Eine importieren, die andere voll qualifiziert nutzen.
Sichtbarkeits-Übersicht mit Paketen
| Modifier | Eigene Klasse | Selbes Paket | Subklasse (anderes Paket) | Anderes Paket |
|---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | ❌ |
| (kein) | ✅ | ✅ | ❌ | ❌ |
private | ✅ | ❌ | ❌ | ❌ |
Bei Klausur-Fragen "Hat Klasse Z in Paket P Zugriff auf Feld f in Klasse X in Paket Q?" → diese Tabelle ist deine Antwort.
Feinheit bei
protected(Java-Spezialfall): Eine Subklasse in einem anderen Paket darf ein geerbtes protected-Member nur überthis/superoder über eine Referenz vom eigenen Subklassen-Typ nutzen, nicht über eine fremde Instanz der Superklasse. Beispiel:web.OnlineKonto extends bank.Kontodarfthis.saldolesen (geerbt), aberfremdesKonto.saldo(eine reinebank.Konto-Instanz) ist verboten.protectedist also offener als package-private, aber kein freier Zugriff von überall.
// in web.OnlineKonto extends bank.Konto (anderes Paket als bank)
this.saldo = 100; // OK: eigenes geerbtes Member ueber this
OnlineKonto eigenes = new OnlineKonto();
eigenes.saldo = 100; // OK: Zugriff ueber den eigenen Subklassen-Typ
Konto fremd = new Konto();
fremd.saldo = 50; // FEHLER: reine Superklassen-Instanz, protected greift hier nicht
Beispiel: Mini-Projekt-Struktur
src/
├── de/uni/main/
│ └── App.java // package de.uni.main; public class App { ... }
├── de/uni/model/
│ ├── Student.java // package de.uni.model; public class Student { ... }
│ └── Kurs.java
└── de/uni/util/
└── Logger.java // package de.uni.util; public class Logger { ... }
In App.java:
package de.uni.main;
import de.uni.model.Student;
import de.uni.model.Kurs;
import de.uni.util.Logger;
public class App {
public static void main(String[] args) {
Student s = new Student("Anna");
Kurs k = new Kurs("Java");
Logger.log("App gestartet");
}
}
Klausur-Faustregeln
1. package muss erste Code-Zeile sein. Davor nur Kommentare. Sonst Compile-Error.
2. Dateipfad passt zum Paket (Projektkonvention). In IDE-/Maven-/Gradle-Projekten gehört package de.uni.test; in die Datei unter <source-root>/de/uni/test/. Sprachlich bestimmt die package-Zeile nur den voll qualifizierten Namen, aber die Build-Tools erwarten genau diese Ordnerstruktur.
3. import kommt zwischen package und Klasse. Reihenfolge: package → imports → class.
4. java.lang ist auto-importiert. String, System, Math, Object brauchen kein import.
5. Wildcard-Import vs. Einzelimport: java.util.* ist erlaubt, erschwert aber die Lesbarkeit, weil man nicht sofort sieht, welche Klassen tatsächlich genutzt werden. IDE-Standard ist der Einzelimport.
Häufige Stolpersteine
1. Falsche package-Zeile. Wenn die Datei unter src/de/uni/Student.java liegt, aber package com.firma; deklariert, beschwert sich die IDE bzw. das Build-Tool ("declared package does not match expected package"). Entweder die Datei in den passenden Ordner verschieben oder die package-Zeile korrigieren.
2. import * macht Wildcard-Member NICHT zugreifbar. import java.util.* lädt nur Klassen, nicht statische Member. Für PI brauchst du import static java.lang.Math.PI.
3. Inneres Paket nicht implizit importiert. import java.util.* importiert NICHT java.util.concurrent.*. Du musst jede Unterebene separat importieren.
4. package-private vs. public verwechselt. Ohne public ist die Klasse nur im selben Paket nutzbar. Für eine wirklich öffentliche Klasse: public class.
5. protected ≠ "geschützt vor anderen Paketen". Genau das Gegenteil: protected ERLAUBT Zugriff aus anderen Paketen für SUBKLASSEN. package-private wäre stricter.
Klausur-Beispielaufgabe
Beispiel (typischer Klausur-Stil, zur Übung konstruiert).
Gegeben ist folgende Projektstruktur unter dem Source-Root src/:
src/
├── de/uni/model/
│ └── Student.java // public class Student, Feld: protected String name
└── de/uni/main/
└── App.java // soll Student nutzen
(a) Welche package-Zeile gehört an den Anfang von Student.java?
(b) Welche import-Zeile braucht App.java, damit es Student mit kurzem Namen verwenden kann, und wo im Datei-Aufbau steht sie?
(c) App liegt im Paket de.uni.main und ist keine Subklasse von Student. Kann App direkt auf das Feld name (protected) zugreifen? Begründe mit der Sichtbarkeits-Tabelle.
Lösung:
- (a)
package de.uni.model;als erste Code-Zeile (vor dieser Zeile nur Kommentare). Der Source-Rootsrc/zählt nicht zum Paketnamen. - (b)
import de.uni.model.Student;. Die Reihenfolge in der Datei ist fest: zuerst diepackage de.uni.main;-Zeile, dann dieimport-Zeilen, danach diepublic class App. - (c) Nein.
protectederlaubt Zugriff im selben Paket und aus Subklassen, aberAppist in einem anderen Paket (de.uni.mainstattde.uni.model) und keine Subklasse vonStudent. In der Tabelle entspricht das der Spalte "Anderes Paket" fürprotected→ ❌. Lösungswege:nameaufpublicsetzen oder einenpublic String getName()-Getter anbieten.
So liest du solche Aufgaben: Erst die Paketzugehörigkeit jeder Klasse bestimmen, dann pro Zugriff in die Sichtbarkeits-Tabelle schauen (selbes Paket? Subklasse? anderes Paket?).
Interaktiv verstehen
Paket-Baum-Visualizer
Eine Mini-Projekt-Struktur mit 3 Paketen. Klick auf eine Klasse: du siehst, welche Imports sie braucht und welche Sichtbarkeits-Beziehungen zu anderen Klassen existieren.
Wechsle zwischen den Paketen, um zu sehen, wann ein Import nötig wird und wann nicht. So entwickelst du ein Gefühl, wie Pakete und Imports in einem realen Projekt zusammenspielen.
Statische Vorschau (Fallback für PDF/Print) derselben Struktur, die der Visualizer interaktiv macht:
src/ ← Source-Root (kein Teil des Paketnamens)
└── de/uni/
├── main/App.java → package de.uni.main; import de.uni.model.Student;
├── model/Student.java → package de.uni.model; public class Student
└── util/Logger.java → package de.uni.util; public class Logger
Jeder Ordner unter src/ ist ein Stück des Paketnamens; App braucht Imports für Student und Logger, weil beide in anderen Paketen liegen.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Tipp: Bei Klausurfragen zur Sichtbarkeit zwischen Paketen, zeichne dir die Paket-Baum-Struktur kurz auf, markiere die Modifier (public/protected/private/package-private) und gehe die Tabelle durch. Spart Fehler.
Code-Stepper: Schritt für Schritt durchspielen
Drei interaktive Demos zu den Kernmechanismen dieses Themas. Klick Step oder Auto und beobachte, wie sich der aufgelöste Klassenname, die Variablen und die Konsole pro Schritt verändern.
1. Import-Auflösung: voll qualifiziert vs. import
Der Compiler ersetzt den kurzen Namen ArrayList gedanklich durch den voll qualifizierten Namen java.util.ArrayList. Genau das macht der import für dich.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Ohne die import-Zeile wäre exakt derselbe Code nur mit voll qualifiziertem Namen möglich: java.util.ArrayList<String> liste = new java.util.ArrayList<>();. Der import spart dir also nur Tipparbeit, an der Funktion ändert er nichts.
2. Namens-Konflikt auflösen: zwei Date-Klassen
java.util.Date und java.sql.Date heißen beide Date. Du kannst nur eine davon importieren, die andere musst du voll qualifiziert ansprechen.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Merke: Ein zweiter Import import java.sql.Date; zusätzlich zum ersten gäbe einen Compile-Fehler, weil der kurze Name Date dann doppelt belegt wäre. Die saubere Lösung ist immer: eine Klasse importieren, die andere voll qualifiziert nutzen.
3. Sichtbarkeit zwischen Paketen: protected im Zugriffstest
Klasse Konto (Paket bank) hat protected double saldo. Wir prüfen Schritt für Schritt, wer darauf zugreifen darf, der häufigste Klausur-Aufgabentyp.
Interaktive Visualisierung
Interaktive Komponente: probiere sie im Topic-Player oben aus.
Klausur-Tipp: Bei "Hat Klasse Z Zugriff auf Member m?" immer zwei Fragen klären: (1) Liegt Z im selben Paket wie die deklarierende Klasse? (2) Ist Z eine Subklasse, und greift sie über den eigenen Typ (this/super) oder über eine fremde Superklassen-Instanz zu? Mit diesen zwei Fragen plus der Sichtbarkeits-Tabelle löst du solche Aufgaben sicher.
Praxis-Übung
Pakete & Imports, Praxis-Übung
6 Aufgaben zu Paket-Deklaration, Imports, Sichtbarkeits-Regeln.
Klausurfragen mit Lösungen (6)
- F1.Welche Zeile muss in einer Java-Datei ZUERST stehen (nach Kommentaren)?
Antwort: Die package-Deklaration
Erklärung: Reihenfolge ist FEST: package → imports → class. Wenn package falsch oder fehlt, gibt's Compile-Error. import kommt danach, dann erst die Klassen-Deklaration.
- F2.Aus welchem Paket sind Klassen wie String, System, Math, Object IMMER ohne import nutzbar?
Antwort: java.lang
Erklärung: java.lang ist auto-importiert. Deshalb funktioniert System.out.println ohne import. Alle anderen Pakete (java.util, java.io, java.nio) brauchen explizite Imports.
- F3.Eine Klasse OHNE Modifier (z.B. class Helper { ... }) ist von überall im selben Paket zugreifbar.
Antwort: Wahr
Erklärung: RICHTIG. Ohne Modifier ist die Sichtbarkeit package-private (auch 'default'). Im selben Paket erreichbar, in anderen Paketen NICHT (auch nicht via import).
Typ: Wahr/Falsch
- F4.Welcher Import erlaubt direkten Zugriff auf PI (statt Math.PI)?
Antwort: import static java.lang.Math.PI;
Erklärung: import static erlaubt direkten Zugriff auf statische Member. Mit `import static java.lang.Math.PI` schreibst du `double u = 2 * PI * r;` statt `Math.PI`. Wildcard ginge: `import static java.lang.Math.*;`
- F5.Welche Aussagen über Pakete sind RICHTIG?
Richtige Antworten: Paket-Namen sind kleingeschrieben (Konvention); package-Deklaration muss vor allen imports stehen; In IDE-/Maven-/Gradle-Projekten muss die Datei-Position (relativ zum Source-Root) zum Paket passen; java.lang ist auto-importiert
Erklärung: Richtig: lowercase, package vor import, java.lang ist auto. Auch richtig: In gängigen IDE-/Maven-/Gradle-Projekten muss der Dateipfad relativ zum Source-Root zum Paket passen (Tooling-Konvention; sprachlich bestimmt die package-Zeile allein den voll qualifizierten Namen). Falsch: Wildcard-Import importiert KEINE Unter-Pakete (java.util.concurrent muss separat); für statische Member braucht's `import static`.
Typ: Multi-Select
- F6.Ordne den Sichtbarkeits-Modifier dem Zugriff zwischen Paketen zu:
Zuordnungen:
- public → Überall, auch in anderen Paketen
- protected → Selbes Paket + Subklassen (auch in anderen Paketen)
- (kein Modifier) → Nur im selben Paket
- private → Nur in der eigenen Klasse
Erklärung: Klassische Sichtbarkeits-Matrix. Bei Klausurfragen 'kann Z von Paket P auf X.f zugreifen?' diese Tabelle anlegen.
Typ: Zuordnung
Klausur-Quiz
Klausurfragen mit Lösungen (6)
- F1.Datei unter src/de/uni/test/A.java. Welche package-Deklaration ist korrekt?
Antwort: package de.uni.test;
Erklärung: Der Source-Root (`src/`) zählt NICHT zum Paket-Namen. Paket = Verzeichnis-Pfad RELATIV zum Source-Root, mit Punkten statt Schrägstrichen.
- F2.Klasse A in Paket p1, Klasse B extends A in Paket p2. Welcher Modifier in A erlaubt B, das geerbte Feld f über this.f/super.f zu nutzen?
Antwort: protected
Erklärung: protected: erlaubt Zugriff aus Subklassen, auch in anderen Paketen, allerdings nur über den eigenen Subklassen-Typ (`this.f`/`super.f` oder eine `B`-Referenz), NICHT über eine fremde `A`-Instanz (`A a = new A(); a.f` wäre verboten). package-private wäre zu strikt (nur selbes Paket). private nur in A selbst. public erlaubt, aber nicht nötig.
- F3.Du kannst in einer Java-Datei mehrere package-Deklarationen haben.
Antwort: Falsch
Erklärung: FALSCH. Genau EINE package-Deklaration pro Datei (oder gar keine = default-Paket). Mehrere imports sind erlaubt, aber package ist einmalig.
Typ: Wahr/Falsch
- F4.Du importierst java.util.Date und java.sql.Date in derselben Datei. Was passiert?
Antwort: Compile-Fehler, Namens-Konflikt
Erklärung: Compile-Fehler: zwei Imports mit gleichem Klassennamen sind nicht erlaubt. Lösung: einen importieren, den anderen voll qualifiziert nutzen (`java.sql.Date dbDate = ...`).
- F5.Pakete sind {{1}} geschrieben. Die {{2}}-Deklaration muss die ERSTE Code-Zeile sein. Klassen aus {{3}} sind automatisch importiert. Ohne Modifier ist eine Klasse {{4}} (auch default genannt).
Lösungen pro Lücke:
- {{1}}: klein / kleingeschrieben / lowercase
- {{2}}: package
- {{3}}: java.lang
- {{4}}: package-private / package private
Erklärung: Standard-Pflichtwissen über Pakete. lowercase-Konvention, package zuerst, java.lang auto, package-private als Default.
Typ: Lückentext
- F6.Sortiere die Reihenfolge in einer Java-Datei:
Richtige Reihenfolge:
- Kommentar / Lizenz-Header
- package de.uni.test;
- import java.util.ArrayList; (und weitere)
- public class MyClass { ... }
Erklärung: Reihenfolge ist FEST in Java: optionale Kommentare → package (genau 1) → imports (beliebig viele) → Klassen. Tauschen → Compile-Error.
Typ: Reihenfolge