Java 9 ha incorporato l'API in una raccolta di moduli. Pertanto, la modularità è il tema centrale; questo design del programma interessato dal livello più alto. I programmi possono essere costruiti in modo modulare fin dall'inizio. Non sorprende che ci saranno API per gestire specificamente l'elemento di programmazione chiamato module . Le API forniscono un modo per accedere ai moduli a livello di codice. Queste API sono molto utili per ottenere informazioni specifiche sui moduli o per leggerli o manipolarli. Questo articolo esplora le classi delle API del modulo e alcuni dei metodi, con esempi per darti un'idea della loro funzionalità generale.
Una panoramica
Java 9 fornisce un insieme di classi e interfacce per gestire i moduli in modo programmatico. Queste API sono particolarmente utili per:
- Lettura, caricamento e ricerca di moduli
- Lettura e manipolazione dei descrittori dei moduli
L'elenco delle API è racchiuso principalmente all'interno dei pacchetti:java.lang e java.lang.module . Sebbene il java.lang.module il pacchetto è costituito dalla maggior parte delle classi e delle interfacce per gestire i descrittori dei moduli, il java.lang il pacchetto contiene classi Modulo , ModuleLayer e un'eccezione, LayerInstantiationException . Tra questi tre, il Modulo class è di primaria importanza perché un'istanza di questa classe fornisce tutti i metodi connessi alla lettura, al caricamento e alla ricerca dei moduli. La classe più importante nel java.lang.module pacchetto è il ModuleDescriptor . Questa classe fornisce i metodi necessari per gestire i descrittori dei moduli.
API dei moduli
Secondo la documentazione dell'API Java, la classe del modulo rappresenta sia i moduli di runtime denominati che quelli senza nome. I moduli con nome hanno un nome e sono costruiti dalla Java Virtual Machine quando un grafico di moduli viene definito sulla Java virtual machine per creare un module layer. Un modulo senza nome non ha un nome. C'è un modulo senza nome per ogni ClassLoader , ottenuto invocando il suo getUnnamedModule metodo. Tutti i tipi che non sono in un modulo denominato sono membri del modulo senza nome del caricatore di classi che definisce.
È semplice scoprire il modulo di una classe a cui appartiene. Ad esempio, se vogliamo scoprire il modulo di una classe, diciamo ArrayList , dall'API Collection o, ad esempio, da Applicazione da JavaFX, potremmo farlo nel modo seguente.
Class<ArrayList> c= ArrayList.class; Module mod=c.getModule(); System.out.println(mod.getName());
Oppure, in un'unica affermazione, come segue:
System.out.println(Application.class .getModule().getName());
Questo stampa il nome del modulo della classe, come java.base , per Elenco array e javafx.graphics per Applicazione . Poiché un modulo può essere nominato o senza nome, possiamo scoprirlo invocando isNamed() metodo. Questo metodo restituisce true se il modulo è denominato o falso se è un modulo senza nome. Ecco un esempio di moduli senza nome.
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()); } }
Uscita:
unnamed module @4c75cab9 null null is Unnamed Module null
E, per i moduli con nome, possiamo scrivere come segue:
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()); } }
Uscita:
module java.base java.base java.base is Named Module module { name: [email protected], uses: [java.nio.file.spi.FileTypeDetector, ...}
Un ModuleLayer contiene solo moduli denominati. Possiamo invocare getLayer metodo per ottenere le informazioni sul livello che contiene nel modulo. Se restituisce null, significa che il modulo non è in un livello o è un modulo senza nome. Se vogliamo ottenere un elenco di pacchetti disponibili in un modulo, possiamo invocare getPackages metodo. getClassLoader restituisce il caricatore di classi del modulo. Ecco un esempio per illustrare i metodi sopra descritti.
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); } } }
Uscita:
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
Descrizione del modulo
Secondo la documentazione dell'API Java 9, "Un descrittore di modulo descrive un modulo denominato e definisce i metodi per ottenere ciascuno dei suoi componenti". Il descrittore del modulo per un modulo denominato nella macchina virtuale Java si ottiene richiamando il Modulo è getDescriptor metodo. I descrittori dei moduli possono anche essere creati utilizzando ModuleDescriptor.Builder class o leggendo la forma binaria di una dichiarazione di modulo (module-info.class ) utilizzando il lettura metodi definiti in questa classe.
Pertanto, in genere il ModuleDescriptor istanza rappresenta la definizione del modulo trovata nella forma binaria del file descrittore del modulo, chiamato module-info.class . Oltre a leggere e manipolare la definizione dei moduli, possiamo usare il ModuleDescriptor.Builder class per descrivere il modulo in fase di esecuzione.
Un descrittore di modulo descrive tre tipi di modulo, come i moduli normali, aperti e automatici.
Un modulo normale e uno aperto descrivono esplicitamente i servizi che forniscono o utilizzano, le dipendenze, i pacchetti esportati e altri componenti. La principale differenza tra un modulo normale e un modulo aperto è che I moduli normali possono aprire pacchetti specifici. Il descrittore di modulo per un modulo aperto non dichiara alcun pacchetto aperto (il suo opens restituisce un set vuoto), ma quando istanziato nella macchina virtuale Java, viene trattato come se tutti i pacchetti fossero aperti.
Il modulo automatico, tuttavia, non dichiara alcun pacchetto aperto, esportato o dipendenza, ad eccezione della dichiarazione implicita di java.base modulo. Quando un modulo automatico viene istanziato nella macchina virtuale Java, legge ogni modulo senza nome e viene trattato come se tutti i pacchetti fossero esportati e aperti.
Il getDescriptor metodo del Modulo class restituisce un'istanza di ModuleDescriptor classe. Il ModuleDescriptor class contiene classi nidificate statiche la cui istanza rappresenta l'istruzione direttiva nel file di dichiarazione del modulo. La classe, tuttavia, non contiene usi istruzione che in genere può essere rappresentata da un'istanza del servizio String . Ecco gli altri quattro:
- ModuleDescriptor.Richiede
- ModuleDescriptor.Apre
- ModuleDescriptor.Provides
- ModuleDescriptor.Esportazioni
Un rapido esempio
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()); } }
Uscita:
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]
Il file binario del descrittore del modulo, chiamato module-info.class , può essere letto direttamente nel modo seguente per creare un'istanza di ModuleDescriptor classe:
try { ModuleDescriptor descriptor = ModuleDescriptor .read(new FileInputStream("module-info.class")); } catch (IOException ex) { }
Esistono quattro versioni della lettura statica sovraccaricata metodo definito nel ModuleDescriptor classe. Vengono utilizzati per leggere la forma binaria della descrizione del modulo da un flusso di input o da un buffer di byte. Ecco l'estrazione dalla documentazione dell'API Java 9.
- leggi(InputStream in) :legge la forma binaria di una dichiarazione di modulo da un flusso di input come descrittore di modulo.
- read(InputStream in, Supplier
> packageFinder) :legge la forma binaria di una dichiarazione di modulo da un flusso di input come descrittore di modulo. - leggi(ByteBuffer bb) :legge la forma binaria di una dichiarazione di modulo da un buffer di byte come descrittore di modulo.
- read(ByteBuffer bb, Supplier
> packageFinder) :legge la forma binaria di una dichiarazione di modulo da un buffer di byte come descrittore di modulo.
I pacchetti impostati da packageFinder includere tutti i pacchetti che il modulo esporta, apre, i servizi forniti e il pacchetto della classe principale che non sono codificati dal descrittore fornito nel flusso di input o nel buffer di byte.
Conclusione
Oltre a leggere le informazioni di base sul modulo, il Modulo class fornisce alcuni metodi chiave per richiedere informazioni sullo stato del modulo, se è letto, aperto, esportato e così via. L'API fornisce anche metodi come addOpens , aggiungi Esporta , aggiungiUsi e aggiungi letture per aggiungere apri ed esporta usi e leggi istruzioni al descrittore di moduli a livello di codice. In poche parole, l'API del modulo fornisce molti altri metodi per gestire in modo specifico i moduli a livello di codice. Qui, abbiamo appena graffiato la superficie per dare un'idea iniziale di cosa si tratta.