Java 9 włączyła API do kolekcji modułów. Dlatego centralnym tematem jest modułowość; wpłynęło to na projekt programu z najwyższego poziomu. Programy mogą być od początku budowane modułowo. Nie jest niespodzianką, że pojawią się interfejsy API zajmujące się konkretnie elementem programowania zwanym modułem . Interfejsy API zapewniają sposób programowego dostępu do modułów. Te interfejsy API są bardzo przydatne, aby uzyskać szczegółowe informacje o modułach lub je odczytać lub manipulować. W tym artykule omówiono klasy interfejsów API modułu i niektóre metody, wraz z przykładami, aby dać wyobrażenie o ich ogólnej funkcjonalności.
Przegląd
Java 9 zapewnia zestaw klas i interfejsów do programowego radzenia sobie z modułem. Te interfejsy API są szczególnie przydatne w przypadku:
- Czytanie, ładowanie i wyszukiwanie modułów
- Odczytywanie i manipulowanie deskryptorami modułów
Lista API jest zawarta głównie w pakietach:java.lang i java.lang.module . Chociaż java.lang.module pakiet składa się z większości klas i interfejsów do obsługi deskryptorów modułów, java.lang pakiet zawiera klasy Moduł , ModuleLayer i wyjątek LayerInstantiationException . Wśród tych trzech Moduł Klasa ma pierwszorzędne znaczenie, ponieważ instancja tej klasy udostępnia wszystkie metody związane z odczytywaniem, ładowaniem i wyszukiwaniem modułów. Najważniejsza klasa w java.lang.module pakiet to ModuleDescriptor . Ta klasa zapewnia niezbędne metody do obsługi deskryptorów modułów.
Moduły API
Zgodnie z dokumentacją Java API, klasa modułu reprezentuje zarówno nazwane, jak i nienazwane moduły wykonawcze. Nazwane moduły mają nazwę i są konstruowane przez wirtualną maszynę Java, gdy graf modułów jest zdefiniowany w wirtualnej maszynie Java w celu utworzenia warstwy modułów. Moduł bez nazwy nie ma nazwy. Dla każdego ClassLoader istnieje nienazwany moduł , uzyskany przez wywołanie jego getUnnamedModule metoda. Wszystkie typy, które nie znajdują się w nazwanym module, są członkami nienazwanego modułu definiującego moduł ładujący klasy.
Łatwo jest znaleźć moduł klasy, do której należy. Na przykład, jeśli chcemy poznać moduł klasy, powiedzmy ArrayList , z interfejsu Collection API lub powiedzmy Aplikacji z JavaFX, możemy to zrobić w następujący sposób.
Class<ArrayList> c= ArrayList.class; Module mod=c.getModule(); System.out.println(mod.getName());
Lub w jednym oświadczeniu w następujący sposób:
System.out.println(Application.class .getModule().getName());
Spowoduje to wypisanie nazwy modułu klasy, na przykład java.base , dla Lista tablic i javafx.graphics dla zgłoszenia . Ponieważ moduł może być nazwany lub nienazwany, możemy to sprawdzić, wywołując isNamed() metoda. Ta metoda zwraca prawdę jeśli moduł ma nazwę lub fałsz jeśli jest to moduł bez nazwy. Oto przykład nienazwanych modułów.
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()); } }
Wyjście:
unnamed module @4c75cab9 null null is Unnamed Module null
A dla nazwanych modułów możemy napisać następująco:
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()); } }
Wyjście:
module java.base java.base java.base is Named Module module { name: [email protected], uses: [java.nio.file.spi.FileTypeDetector, ...}
ModuleLayer zawiera tylko nazwane moduły. Możemy wywołać getLayer metody, aby uzyskać informacje o warstwie, którą zawiera w module. Jeśli zwraca null, oznacza to, że moduł nie znajduje się w warstwie lub jest modułem nienazwanym. Jeśli chcemy uzyskać listę pakietów dostępnych w module, możemy wywołać getPackages metoda. getClassLoader Metoda zwraca moduł ładujący klasy. Oto przykład ilustrujący metody opisane powyżej.
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); } } }
Wyjście:
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
Opis modułu
Według dokumentacji Java 9 API „Deskryptor modułu opisuje nazwany moduł i definiuje metody uzyskiwania każdego z jego komponentów”. Deskryptor modułu dla nazwanego modułu w wirtualnej maszynie Java jest uzyskiwany przez wywołanie Modułu getDescriptor metoda. Deskryptory modułów można również tworzyć za pomocą ModuleDescriptor.Builder class lub czytając binarną formę deklaracji modułu (module-info.class ) za pomocą odczytu metody zdefiniowane w tej klasie.
Dlatego zazwyczaj ModuleDescriptor instancja reprezentuje definicję modułu znalezioną w postaci binarnej pliku deskryptora modułu o nazwie module-info.class . Oprócz czytania i manipulowania definicją modułu, możemy użyć ModuleDescriptor.Builder klasę opisującą moduł w czasie wykonywania.
Deskryptor modułu opisuje trzy typy modułów, takie jak moduły normalne, otwarte i automatyczne.
Zwykły i otwarty moduł wyraźnie opisują usługi, które dostarczają lub używają, zależności, eksportowane pakiety i inne komponenty. Główna różnica między zwykłym a otwartym modułem polega na tym, że Normalne moduły mogą otwierać określone pakiety. Deskryptor modułu dla otwartego modułu nie deklaruje żadnych otwartych pakietów (jego otwiera się Metoda zwraca pusty zestaw), ale po utworzeniu instancji w wirtualnej maszynie Java jest traktowana tak, jakby wszystkie pakiety były otwarte.
Moduł automatyczny nie deklaruje jednak żadnych eksportowanych, otwartych pakietów ani zależności, z wyjątkiem niejawnej deklaracji java.base moduł. Gdy automatyczny moduł jest tworzony na wirtualnej maszynie Java, odczytuje każdy nienazwany moduł i jest traktowany tak, jakby wszystkie pakiety zostały wyeksportowane i otwarte.
getDescriptor metoda Modułu klasa zwraca instancję ModuleDescriptor klasa. ModuleDescriptor class zawiera statyczne klasy zagnieżdżone, których instancja reprezentuje instrukcję dyrektywy w pliku deklaracji modułu. Klasa nie zawiera jednak zastosowań oświadczenie, które zazwyczaj może być reprezentowane przez instancję usługi String . Oto pozostałe cztery:
- ModuleDescriptor.Requires
- ModuleDescriptor.Opens
- ModuleDescriptor.Provides
- ModuleDescriptor.Exports
Szybki przykład
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()); } }
Wyjście:
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]
Plik binarny deskryptora modułu o nazwie module-info.class , można bezpośrednio odczytać w następujący sposób, aby utworzyć instancję ModuleDescriptor klasa:
try { ModuleDescriptor descriptor = ModuleDescriptor .read(new FileInputStream("module-info.class")); } catch (IOException ex) { }
Istnieją cztery wersje przeciążonego odczytu statycznego metoda zdefiniowana w ModuleDescriptor klasa. Służą do odczytywania binarnej postaci opisu modułu ze strumienia wejściowego lub bufora bajtów. Oto wyciąg z dokumentacji API Java 9.
- odczyt(InputStream w) :Czyta binarną formę deklaracji modułu ze strumienia wejściowego jako deskryptor modułu.
- odczytaj (InputStream w, Dostawca
> PackageFinder) :Czyta binarną formę deklaracji modułu ze strumienia wejściowego jako deskryptor modułu. - odczyt(ByteBuffer bb) :Czyta binarną formę deklaracji modułu z bufora bajtowego jako deskryptor modułu.
- odczyt(ByteBuffer bb, Dostawca
> packageFinder) :Czyta binarną formę deklaracji modułu z bufora bajtowego jako deskryptor modułu.
Zestaw pakietów przez packageFinder Uwzględnij wszystkie pakiety, które moduł eksportuje, otwiera, udostępnia usługi oraz pakiet głównej klasy, które nie są zakodowane przez deskryptor dostarczony w strumieniu wejściowym lub buforze bajtowym.
Wniosek
Oprócz zapoznania się z podstawowymi informacjami o module, Moduł class udostępnia kilka kluczowych metod do zapytania o stan modułu — czy jest on odczytany, otwarty, wyeksportowany i tak dalej. Interfejs API udostępnia również metody, takie jak addOpens , dodajEksport , addUżycia i dodajCzytaj programowe dodawanie otwartych i eksportowanych zastosowań oraz instrukcji odczytu do deskryptora modułów. Krótko mówiąc, interfejs API modułu zapewnia wiele innych metod do programowego radzenia sobie z modułami. Tutaj właśnie zarysowaliśmy powierzchnię, aby dać pierwsze wyobrażenie o tym, o co w tym wszystkim chodzi.