Java 9 integreerde de API in een verzameling modules. Modulariteit is daarom het centrale thema; dit beïnvloedde het ontwerp van het programma vanaf het hoogste niveau. Programma's kunnen vanaf het begin modulair worden opgebouwd. Het is geen verrassing dat er API's zullen zijn die specifiek omgaan met het programmeerelement dat een module wordt genoemd . De API's bieden een manier om programmatisch toegang te krijgen tot modules. Deze API's zijn erg handig om specifieke informatie over de modules te krijgen of om ze te lezen of te manipuleren. In dit artikel worden de klassen van Module-API's en enkele methoden onderzocht, met voorbeelden om u een idee te geven van hun algemene functionaliteit.
Een overzicht
Java 9 biedt een reeks klassen en interfaces om programmatisch met modules om te gaan. Deze API's zijn met name handig voor:
- Lezen, laden en zoeken in modules
- Lezen en manipuleren van modulebeschrijvingen
De lijst met API's is voornamelijk opgenomen in pakketten:java.lang en java.lang.module . Hoewel de java.lang.module pakket bestaat uit de meeste klassen en interfaces om met moduledescriptors om te gaan, de java.lang pakket bevat klassen Module , ModuleLayer , en een uitzondering, LayerInstantiationException . Van deze drie is de Module class is van primair belang omdat een instantie van deze klasse alle methoden biedt die verband houden met het lezen, laden en zoeken van modules. De belangrijkste klasse in de java.lang.module pakket is de ModuleDescriptor . Deze klasse biedt de nodige methoden om met modulebeschrijvingen om te gaan.
Modules-API
Volgens Java API-documentatie vertegenwoordigt de moduleklasse zowel benoemde als niet-benoemde runtime-modules. Benoemde modules hebben een naam en worden geconstrueerd door de Java Virtual Machine wanneer een grafiek van modules wordt gedefinieerd voor de Java virtual machine om een modulelaag te creëren. Een naamloze module heeft geen naam. Er is een niet nader genoemde module voor elke ClassLoader , verkregen door zijn getUnnamedModule . aan te roepen methode. Alle typen die niet in een benoemde module zitten, zijn leden van de naamloze module van hun bepalende klasselader.
Het is eenvoudig om de module te achterhalen van een klasse waartoe deze behoort. Als we bijvoorbeeld de module van een klasse willen weten, zeg dan ArrayList , van de Collection API of, laten we zeggen, Applicatie van JavaFX, kunnen we dit op de volgende manier doen.
Class<ArrayList> c= ArrayList.class; Module mod=c.getModule(); System.out.println(mod.getName());
Of, in een enkele verklaring, als volgt:
System.out.println(Application.class .getModule().getName());
Dit drukt de modulenaam van de klasse af, zoals java.base , voor Arraylijst , en javafx.graphics voor Toepassing . Omdat een module een naam of een naam kan hebben, kunnen we dit achterhalen door de isNamed() aan te roepen methode. Deze methode retourneert true als de module een naam heeft of false als het een niet nader genoemde module is. Hier is een voorbeeld van niet nader genoemde modules.
package org.mano.java9.examples; public class Main { public static void main(String[] args) { Class<Main> c= Main.class; Module mod=c.getModule(); System.out.println(mod); System.out.println(mod.getName()); System.out.println(mod.getName()+" is " +(mod.isNamed()? "Named Module":"Unnamed Module")); System.out.println(mod.getDescriptor()); } }
Uitvoer:
unnamed module @4c75cab9 null null is Unnamed Module null
En voor benoemde modules kunnen we als volgt schrijven:
package org.mano.java9.examples; import java.util.ArrayList; public class Main { public static void main(String[] args) { Class<ArrayList> c= ArrayList.class; Module mod=c.getModule();< System.out.println(mod); System.out.println(mod.getName()); System.out.println(mod.getName()+" is " +(mod.isNamed()? "Named Module":"Unnamed Module")); System.out.println(mod.getDescriptor()); } }
Uitvoer:
module java.base java.base java.base is Named Module module { name: [email protected], uses: [java.nio.file.spi.FileTypeDetector, ...}
Een ModuleLayer bevat alleen benoemde modules. We kunnen de getLayer . aanroepen methode om de informatie te krijgen over de laag die het in de module bevat. Als het null retourneert, betekent dit dat de module zich niet in een laag bevindt, of dat het een niet nader genoemde module is. Als we een lijst willen krijgen met pakketten die beschikbaar zijn in een module, kunnen we de getPackages aanroepen methode. De getClassLoader methode retourneert de module klasse loader. Hier is een voorbeeld om de hierboven beschreven methoden te illustreren.
package org.app.module1; import javafx.application.Application; import java.util.Set; public class Main { public static void main(String[] args) { Class<Application> c = Application.class; Module mod = c.getModule(); System.out.println("Name :" + mod.getName()); System.out.println(mod.getName() + " is " + (mod.isNamed() ? "Named Module" : "Unnamed Module")); System.out.println("Layer :" + mod.getLayer()); System.out.println("ClassLoader :" + mod.getClassLoader()); System.out.println("List of Packagesn....................."); Set<String> set = mod.getPackages(); int i=1; for (String s : set) { System.out.println(i+++") "+s); } } }
Uitvoer:
Name :javafx.graphics javafx.graphics is Named Module Layer :jdk.compiler, java.compiler, jdk.management.jfr, jdk.scripting.nashorn, ... ClassLoader :jdk.internal.loader.ClassLoaders [email protected] .................... List of Packages ..................... 1) com.sun.javafx.stage 2) com.sun.scenario.effect.impl.prism.ps 3) javafx.print ... 107) com.sun.prism.j2d 108) javafx.scene.image
Modulebeschrijving
Volgens Java 9 API-documentatie:"Een moduledescriptor beschrijft een benoemde module en definieert methoden om elk van zijn componenten te verkrijgen." De moduledescriptor voor een benoemde module in de Java virtual machine wordt verkregen door de Module aan te roepen 's getDescriptor methode. Modulebeschrijvingen kunnen ook worden gemaakt met behulp van de ModuleDescriptor.Builder class of door de binaire vorm van een moduledeclaratie te lezen (module-info.class ) met behulp van de lees methoden gedefinieerd in deze klasse.
Daarom is meestal de ModuleDescriptor instantie vertegenwoordigt de moduledefinitie gevonden in de binaire vorm van het moduledescriptorbestand, genaamd module-info.class . Naast het lezen en manipuleren van moduledefinities, kunnen we de ModuleDescriptor.Builder gebruiken class om de module tijdens runtime te beschrijven.
Een moduledescriptor beschrijft drie soorten modules, zoals normale, open en automatische modules.
Een normale en een open module beschrijven expliciet de diensten die ze leveren of gebruiken, afhankelijkheden, geëxporteerde pakketten en andere componenten. Het belangrijkste verschil tussen een normale module en een open module is dat Normale modules specifieke pakketten kunnen openen. De moduledescriptor voor een open module declareert geen open pakketten (zijn opens methode retourneert een lege set), maar wanneer geïnstantieerd in de Java virtual machine, wordt het behandeld alsof alle pakketten open zijn.
De automatische module declareert echter geen geëxporteerde, geopende pakketten of afhankelijkheden, behalve impliciete declaratie van de java.base module. Wanneer een automatische module wordt geïnstantieerd in de virtuele Java-machine, leest deze elke niet nader genoemde module en wordt behandeld alsof alle pakketten zijn geëxporteerd en geopend.
De getDescriptor methode van de Module class retourneert een instantie van de ModuleDescriptor klas. De ModuleDescriptor class bevat statische geneste klassen waarvan de instantie de instructie-instructie in het moduledeclaratiebestand vertegenwoordigt. De klasse bevat echter geen gebruiken instructie die doorgaans kan worden weergegeven door een service-instantie String . Dit zijn die andere vier:
- ModuleDescriptor.Vereist
- ModuleDescriptor.Opent
- ModuleDescriptor.Provides
- ModuleDescriptor.Exports
Een snel voorbeeld
package org.mano.java9.examples; import javax.sql.RowSet; import java.lang.module.ModuleDescriptor; import java.util.List; public class Main { public static void main(String[] args) { System.out.println("Module Name: " + List.class.getModule().getName()); show(List.class.getModule().getDescriptor()); System.out.println("Module Name: " + RowSet.class.getModule().getName()); show(RowSet.class.getModule().getDescriptor()); } public static void show(ModuleDescriptor d) { System.out.println("Module Descriptionn-------------------------"); System.out.println("Requires: " + d.requires()); System.out.println("Exports: " + d.exports()); System.out.println("Uses: " + d.uses()); System.out.println("Provides: " + d.provides()); System.out.println("Packages: " + d.packages()); } }
Uitvoer:
Module Name: java.base Module Description ------------------------- Requires: [] Exports: [jdk.internal.org.objectweb.asm.signature to [jdk.scripting.nashorn], ...] Uses: [java.util.spi.LocaleNameProvider, java.nio.file.spi.FileSystemProvider, ...] Provides: [java.nio.file.spi.FileSystemProvider with [jdk.internal.jrtfs.JrtFileSystemProvider]] Packages: [java.nio.file, jdk.internal.org.objectweb.asm .tree.analysis, com.sun.security.ntlm, ...] Module Name: java.sql Module Description ------------------------- Requires: [mandated java.base, transitive java.logging, transitive java.xml] Exports: [java.sql, javax.transaction.xa, javax.sql] Uses: [java.sql.Driver] Provides: [] Packages: [javax.sql, javax.transaction.xa, java.sql]
Het binaire bestand van de modulebeschrijving, genaamd module-info.class , kan op de volgende manier direct worden gelezen om een instantie van de ModuleDescriptor te maken klas:
try { ModuleDescriptor descriptor = ModuleDescriptor .read(new FileInputStream("module-info.class")); } catch (IOException ex) { }
Er zijn vier versies van de overbelaste statische lees methode gedefinieerd in de ModuleDescriptor klas. Ze worden gebruikt om de binaire vorm van de modulebeschrijving uit een invoerstroom of een bytebuffer te lezen. Hier is de extractie uit Java 9 API-documentatie.
- lezen(InputStream in) :Leest de binaire vorm van een moduledeclaratie van een invoerstroom als een moduledescriptor.
- read(InputStream in, Supplier
> packageFinder) :Leest de binaire vorm van een moduledeclaratie van een invoerstroom als een moduledescriptor. - read(ByteBuffer bb) :Leest de binaire vorm van een moduledeclaratie uit een bytebuffer als moduledescriptor.
- read(ByteBuffer bb, leverancier
> packageFinder) :Leest de binaire vorm van een moduledeclaratie uit een bytebuffer als moduledescriptor.
De ingestelde pakketten door packageFinder omvatten alle pakketten die de module exporteert, opent, geleverde services en het pakket van de hoofdklasse die niet zijn gecodeerd door de descriptor die wordt geleverd in de invoerstroom of bytebuffer.
Conclusie
Naast het lezen van basisinformatie over de module, kan de Module class biedt enkele belangrijke methoden om te informeren naar de modulestatus, of deze nu gelezen, geopend, geëxporteerd, enzovoort is. De API biedt ook methoden zoals addOpens , addExport , addUses , en addReads om gebruiks- en leesinstructies voor openen en exporteren toe te voegen aan de moduledescriptor programmatisch. In een notendop, de Module API biedt vele andere methoden om specifiek programmatisch met modules om te gaan. Hier hebben we net het oppervlak bekrast om een eerste idee te geven van waar het allemaal om draait.