W3docs

Java Modultypen

Named, Automatic und Unnamed Module in Java und deren Zusammenspiel bei Kompilierung und Ausführung.

Das Java Platform Module System (JPMS) kennt drei Arten von Modulen. Nur eine davon ist das „echte" Modul, das Sie selbst schreiben; die anderen beiden existieren, damit die Millionen von JARs aus der Zeit vor Java 9 weiterhin funktionieren. Zu verstehen, welche Art aus einem bestimmten JAR wird — und dass dies ausschließlich davon abhängt, wo Sie es ablegen — ist der Schlüssel zur schmerzfreien Migration. Diese Seite definiert alle drei Arten, zeigt die Zugriffsregeln zwischen ihnen und belegt die Kategorien mit einem ausführbaren Programm.

Named-Module

Ein Named (explizites) Modul ist eines mit einer module-info.class, das auf dem Modulpfad (--module-path / -p) liegt. Es ist das vollwertige Mitglied:

  • Es hat einen Namen aus seinem Deskriptor.
  • Es liest nur die Module, die es per requires angibt.
  • Es gibt nur die Pakete frei, die es per exports deklariert.

Dies ist das stark gekapseltes Modul, das das Kapitel zur Moduldeklaration beschrieben hat. Alles, was JPMS verspricht — deklarierte Abhängigkeiten, versteckte Interna, frühzeitige Fehlererkennung — gilt für Named-Module.

Automatic-Module

Ein Automatic-Modul ist ein einfaches JAR (ohne module-info), das auf dem Modulpfad abgelegt wird. JPMS hüllt es in ein Modul, damit Named-Module es während der Migration per requires einbinden können — ohne darauf warten zu müssen, dass der Bibliotheksautor einen Deskriptor hinzufügt. Ein Automatic-Modul:

  • Erhält einen Namen, der aus dem JAR-Dateinamen abgeleitet wird (z. B. guava-32.1.jarguava), sofern das JAR-Manifest nicht Automatic-Module-Name setzt.
  • Exportiert jedes Paket — es hat keine exports-Direktive, sodass alle Pakete für alle zugänglich sind.
  • Liest jedes andere Modul, einschließlich des Unnamed-Moduls, und kann damit weiterhin Classpath-JARs sehen.

Es ist eine Brücke: Es erlaubt Ihnen, mit dem Schreiben von Named-Modulen zu beginnen, die von noch nicht modularisierten Bibliotheken abhängen. Der Preis ist, dass es vollständig auf Kapselung verzichtet, und sein automatisch abgeleiteter Name kann sich ändern, wenn das JAR umbenannt wird — weshalb Automatic-Module-Name im Manifest das Verantwortungsbewusste ist, das eine Bibliothek mitliefern sollte.

Das Unnamed-Modul

Das Unnamed-Modul ist der Sammelbehälter für den Classpath. Jede Klasse, die vom Classpath geladen wird, gehört zum Unnamed-Modul ihres Classloaders. Es:

  • Hat keinen Namen (getName() gibt null zurück, isNamed() ist false).
  • Liest jedes andere Modul im System.
  • Exportiert alle seine Pakete an andere Unnamed/Automatic-Module.

Doch es gibt eine bewusste Einbahnstraße: Ein Named-Modul kann das Unnamed-Modul nicht per requires einbinden. Sie können es nicht benennen, also können Sie auch nicht von ihm abhängen. Dies ist die Regel, die die Migrationsreihenfolge erzwingt — ein Named-Modul darf nur von anderen Named- oder Automatic-Modulen abhängen, niemals von reinem Classpath-Code.

Die Zugriffsmatrix

Wer wen lesen kann, lässt sich in einer kleinen Tabelle zusammenfassen:

Von ↓ / Nach →NamedAutomaticUnnamed
Namednur bei requiresnur bei requiresniemals
Automaticjajaja
Unnamedjajaja

Die einzige restriktive Zelle — Named-Code kann Unnamed-Code nicht erreichen — erklärt vollständig, warum die Migration von unten nach oben erfolgt (im nächsten Kapitel behandelt).

Ein praktisches Beispiel: Modulart zur Laufzeit bestimmen

Die Module API teilt Ihnen für jede Klasse mit, ob ihr Modul named ist und ob es automatisch synthetisiert wurde. Dieses Programm untersucht drei Referenzen — seine eigene Klasse (Classpath → Unnamed), einen JDK-Typ (Named) und gibt den Boot-Layer aus — um die Kategorien greifbar zu machen.

java— editable, runs on the server

Was die Ausgabe zeigt:

  • Die eigene Klasse des Programms wurde als UNNAMED mit null-Name klassifiziert, während java.util.List und HttpClient als NAMED eingestuft wurden (java.base, java.net.http). Beim Ausführen vom Classpath ist Ihr Code immer unnamed; das JDK ist immer eine Sammlung von Named-Modulen. Die Art eines Moduls wird durch die Art des Ladens bestimmt, nicht durch irgendetwas in der Klasse selbst.
  • java.base.canRead(self) gab false zurück, aber self.canRead(java.base) gab true zurück. Das ist die Einbahnstraße in Aktion: Das Unnamed-Modul liest alles, aber kein Named-Modul liest das Unnamed-Modul. Diese Asymmetrie ist genau der Grund, warum Named-Code kein requires auf Classpath-Code setzen kann.
  • classify() unterschied Automatic von Named durch descriptor.isAutomatic(). Sie werden hier kein true sehen (nichts wurde als einfaches JAR auf den Modulpfad gelegt), aber die Prüfung ist genau die, mit der Werkzeuge ein Automatic-Modul erkennen — ein echtes Modulobjekt mit einem synthetisierten, vollständig offenen Deskriptor.
  • isExported("java.util") gab true zurück, aber isExported("jdk.internal.misc") gab false zurück, obwohl beide echte Pakete innerhalb von java.base sind. Die exports-Liste eines Named-Moduls ist eine Erlaubnisliste; nicht exportierte (oder nur qualifiziert exportierte) Pakete sind für externen Code unsichtbar, unabhängig davon, ob sie public sind. Das Unnamed-Modul hingegen exportiert alles, was es enthält.
  • Für keine dieser Beobachtungen war eine module-info.java nötig. Die drei Kategorien sind Laufzeitfakten darüber, wie eine Klasse geladen wurde, und getModule() sowie getDescriptor() legen sie offen — dieselben Aufrufe, auf die Migrations-Werkzeuge sich stützen, um herauszufinden, womit sie arbeiten.

Warum drei Modularten existieren

Die beiden Kompatibilitätsarten — Automatic und Unnamed — ermöglichen es, dass Java 9+ unmodifizierte Java-8-Anwendungen ausführt. Sie aktivieren starke Kapselung JAR für JAR: Lassen Sie alles auf dem Classpath (alles Unnamed), ändert sich nichts; verschieben Sie eine Bibliothek ohne Deskriptor auf den Modulpfad, wird sie Automatic; fügen Sie eine module-info.java hinzu, wird sie Named. Als Nächstes zeigen Moduldienste den uses/provides-Mechanismus zur Entkopplung von Modulen, und Modulmigration führt ein echtes Projekt durch diese drei Zustände.

Übung

Übung
Während der Migration legen Sie ein einfaches JAR eines Drittanbieters (ohne 'module-info.class') namens 'fastjson-2.0.jar' auf den MODULPFAD und schreiben 'requires fastjson;' in Ihr eigenes Named-Modul. Welche Aussage beschreibt 'fastjson' hier korrekt?
Während der Migration legen Sie ein einfaches JAR eines Drittanbieters (ohne 'module-info.class') namens 'fastjson-2.0.jar' auf den MODULPFAD und schreiben 'requires fastjson;' in Ihr eigenes Named-Modul. Welche Aussage beschreibt 'fastjson' hier korrekt?
Was this page helpful?