[JAVA] Puzzle-Studiennotizen

Eine Notiz aus dem Studium von Java 9 Project Jigsaw.

Umgebung

OS Windows 10

Java

>java --version
java 9
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)

Hello World

Ordnerstruktur

|-main/
| |-class/
| `-src/
|   |-module-info.java
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    |-module-info.java
    `-sample/sub/
      |-api/
      | `-Foo.java
      |-internal/
      | `-FooImpl.java
      |
      `-FooFactory.java

Quellcode

sub/src/sample/sub/api/Foo.java


package sample.sub.api;

public interface Foo {
    void hello();
}

sub/src/sample/sub/internal/FooImpl.java


package sample.sub.internal;

import sample.sub.api.Foo;

public class FooImpl implements Foo {
    @Override
    public void hello() {
        System.out.println("FooImpl.hello()");
    }
}

sub/src/sample/sub/FooFactory.java


package sample.sub;

import sample.sub.api.Foo;
import sample.sub.internal.FooImpl;

public class FooFactory {
    public static Foo newInstance() {
        return new FooImpl();
    }
}

sub/src/module-info.java


module sample_module.sub {
    exports sample.sub;
    exports sample.sub.api;
}

main/src/sample/main/Main.java


package sample.main;

import sample.sub.FooFactory;
import sample.sub.api.Foo;

public class Main {
    public static void main(String... args) {
        Foo foo = FooFactory.newInstance();
        foo.hello();
    }
}

main/src/module-info.java


module sample_module.main {
    requires sample_module.sub;
}

kompilieren

#Kompilieren Sie das Untermodul
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\FooFactory.java sub\src\sample\sub\api\Foo.java sub\src\sample\sub\internal\FooImpl.java

#Kompilieren Sie das Hauptmodul
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

Lauf

> java -p main\class;sub\class -m sample_module.main/sample.main.Main
FooImpl.hello()

Erläuterung

Abhängige Moduldeklaration

sub/src/module-info.java


module sample_module.sub {
    exports sample.sub;
    exports sample.sub.api;
}

--Deklarieren Sie das Modul in einer speziellen Datei namens "module-info.java", die im Root-Paket abgelegt ist.

Referenzierung der Moduldeklaration

main/src/module-info.java


module sample_module.main {
    requires sample_module.sub;
}

Modulspezifikation zur Kompilierungszeit

#Submodul kompilieren
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\FooFactory.java sub\src\sample\sub\api\Foo.java sub\src\sample\sub\internal\FooImpl.java

#Hauptmodul kompilieren
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

--Compile verwendet weiterhin den Befehl javac --Wenn kein abhängiges Modul vorhanden ist, können Sie mit den herkömmlichen Spezifikationen kompilieren (Submodul-Kompilierung)

Modulspezifikation und Hauptklassenspezifikation beim Start

> java -p main\class;sub\class -m sample_module.main/sample.main.Main

Verhalten beim Verweisen auf Pakete, die nicht exportiert werden

Main.java


package sample.main;

import sample.sub.FooFactory;
import sample.sub.api.Foo;
import sample.sub.internal.FooImpl;

public class Main {
    public static void main(String... args) {
        FooImpl foo = (FooImpl)FooFactory.newInstance();
        foo.hello();
    }
}

Fehler beim Kompilieren


> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
main\src\sample\main\Main.java:5:Error:Paketprobe.sub.intern kann nicht angezeigt werden
import sample.sub.internal.FooImpl;
                 ^
  (Paketprobe.sub.intern ist das Modulbeispiel_module.In Sub deklariert, aber nicht exportiert)
1 Fehler

Auf diese Weise können Sie nicht auf Pakete verweisen, die nicht "exportiert" wurden.

Verpackung und Verwendung im Glas

Versuchen Sie es mit dem Hello World-Programm, indem Sie sowohl Haupt- als auch Nebenprogramm in ein Glas packen.

Gleich bis zum Kompilieren mit javac.

Paket im Glas

#Erstellen Sie ein Glas für das Untermodul
> jar -c -f sub\jar\sub-module.jar -C sub\class .

#Erstellen Sie ein Glas für das Hauptmodul
> jar -c -f main\jar\main-module.jar -C main\class .

--Verwenden Sie den Befehl jar wie zuvor, um die Modul-JAR-Datei zu erstellen ---c ist ein Befehl, der bedeutet, dass ein Glas erstellt wird (kurz für --create).

Siehe die Modulinformationen von jar

#Informationen zum Submodul ausgeben
> jar -d -f sub\jar\sub-module.jar
sample_module.sub jar:file:///.../sub/jar/sub-module.jar/!module-info.class
exports sample.sub
exports sample.sub.api
requires java.base mandated
contains sample.sub.internal

#Ausgabeinformationen des Hauptmoduls
> jar -d -f main\jar\main-module.jar
sample_module.main jar:file:///.../main/jar/main-module.jar/!module-info.class
requires java.base mandated
requires sample_module.sub
contains sample.main

-- -d (--describe-module) kann die Modulinformationen von jar ausgeben. --exports ist ein öffentliches Paket --requires ist das abhängige Modul --java.base ist ein Modul, das das Paket java.lang enthält und immer mitgeliefert wird, auch wenn Sie es nicht angeben. --contains ist wahrscheinlich ein privates Paket

Lauf

> java -p sub\jar;main\jar -m sample_module.main/sample.main.Main
FooImpl.hello()

Modultyp

Es gibt drei Haupttypen von Modulen.

  1. named module
  2. automatic module
  3. unnamed module

named module Ein Modul mit Definitionsinformationen (module-info.class), die vom Modulpfad ( --module-path) gelesen werden. Wenn wir über Module sprechen, beziehen wir uns oft auf sie.

automatic module Ein Glas ohne Definitionsinformationen, das im Modulpfad gelesen wird.

Alle Pakete werden als "Exporte" behandelt. Außerdem wird der Modulname automatisch aus dem Namen der JAR-Datei vervollständigt.

Dies ist der Fall, wenn Sie eine vor Java 9 erstellte JAR-Datei mit --module-path angeben.

Ich habe keine klare Definition gefunden, aber es scheint, dass es sich um eine JAR-Datei handeln muss, da der Modulname aus dem Dateinamen vervollständigt wird. Javadoc hat auch die folgende Beschreibung, daher denke ich, dass es mindestens ein Glas sein muss.

A JAR file that does not have a module-info.class in its top-level directory defines an automatic module (Übersetzung) Jar-Dateien ohne module-info.class auf der obersten Ebene definieren ein automatisches Modul

http://download.java.net/java/jigsaw/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-

unnamed module Mit dem Klassenpfad (--class-path) geladene Module. Alle Pakete werden als "Exporte" behandelt.

Kombinieren Sie jedes Modul

Probieren Sie verschiedene Kombinationen jedes Moduls aus (benanntes Modul, automatisches Modul, unbenanntes Modul).

Wenn Sie zuerst die Ergebnisse tabellieren,

jigsaw.jpg

Es sieht aus wie das.

Implementierung (gemeinsam)

sub/src/sample/sub/Sub.java


package sample.sub;

public class Sub {
    public void method() {
        System.out.println("Sub.method()");
    }
}

main/src/sample/main/Main.java


package sample.main;

import sample.sub.Sub;

public class Main {
    public static void main(String... args) {
        Sub sub = new Sub();
        sub.method();
    }
}

named module -> named module Hallo Welt ist das, also werde ich es weglassen.

named module -> automatic module

Ordnerstruktur


|-main/
| |-class/
| `-src/
|   |-module-info.java
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    `-sample/sub/
      `-Sub.java

Submodul kompilieren


#kompilieren
> javac -d sub\class sub\src\sample\sub\Sub.java

#Glas Kreation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

main\src\module-info.java


module sample_module.main {
    requires no.module.sub;
}

Kompilieren Sie das Hauptmodul und starten Sie es


#Hauptmodul kompilieren
> javac -p sub\jar\no_module-sub.jar -d main\class main\src\module-info.java main\src\sample\main\Main.java

#Anlaufen
> java -p sub\jar\no_module-sub.jar;main\class -m sample_module.main/sample.main.Main
Sub.method()

Logik zur Bestimmung des automatischen Modulnamens für das automatische Modul

  1. Manifestattribut Automatic-Module-Name
  2. Wird automatisch aus dem Dateinamen ermittelt, wenn dies nicht in der Manifestdatei angegeben ist

named module -> unnamed module Ich kann es nicht scheinen.

main/src/module-info.java


module sample_module.main {
    // requires no.module.sub;
}
> javac -cp sub\jar\no_module-sub.jar -d main\class main\src\module-info.java main\src\sample\main\Main.java
main\src\sample\main\Main.java:3:Error:Paketprobe.Sub existiert nicht
import sample.sub.Sub;
                 ^
main\src\sample\main\Main.java:7:Error:Symbol kann nicht gefunden werden
        Sub sub = new Sub();
        ^
Symbol:Klasse Sub
Ort:Klasse Main
main\src\sample\main\Main.java:7:Error:Symbol kann nicht gefunden werden
        Sub sub = new Sub();
                      ^
Symbol:Klasse Sub
Ort:Klasse Main
3 Fehler

Selbst wenn ich jar im Klassenpfad (-cp) setze, kann die Klasse nicht gelesen werden.

automatic module -> named module

Ordnerstruktur


|-main/
| |-class/
| `-src/
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    |-module-info.java
    `-sample/sub/
      `-Sub.java

sub/src/module-info.java


module sample_module.sub {
    exports sample.sub;
}

Submodul kompilieren


#kompilieren
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#Glas Kreation
> jar -c -f sub\jar\module-sub.jar -C sub\class .

Hauptmodul kompilieren


#kompilieren
> javac -d main\class --add-modules sample_module.sub -p sub\jar\module-sub.jar main\src\sample\main\Main.java

#Glas Kreation
> jar -c -f main\jar\no_module-main.jar -C main\class .

Lauf


> java -p sub\jar\module-sub.jar;main\jar\no_module-main.jar --add-modules sample_module.sub -m no.module.main/sample.main.Main
Sub.method()

Dies ist eine Vorstellung von Togetter of the Gods, also kann es anders sein oder auch nicht.

automatic module -> automatic module

Ordnerstruktur


|-main/
| |-class/
| `-src/
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    `-sample/sub/
      `-Sub.java

Submodul kompilieren


#kompilieren
> javac -d sub\class sub\src\sample\sub\Sub.java

#Glas Kreation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Hauptmodul kompilieren


#kompilieren
> javac -d main\class -p sub\jar\no_module-sub.jar --add-modules no.module.sub main\src\sample\main\Main.java

# jar 
> jar -c -f main\jar\no_module-main.jar -C main\class .

Anlaufen


> java -p sub\jar\no_module-sub.jar;main\jar\no_module-main.jar --add-modules no.module.sub -m no.module.main/sample.main.Main
Sub.method()

--Dies kann auch durch Angabe von "--add-modules" ausgeführt werden.

automatic module -> unnamed module

Submodul kompilieren


#kompilieren
> javac -d sub\class sub\src\sample\sub\Sub.java

#Glas Kreation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Hauptmodul kompilieren


#kompilieren
> javac -d main\class -cp sub\jar\no_module-sub.jar main\src\sample\main\Main.java

# jar 
> jar -c -f main\jar\no_module-main.jar -C main\class .

Lauf


> java -p main\jar\no_module-main.jar -cp sub\jar\no_module-sub.jar -m no.module.main/sample.main.Main
Sub.method()

--Kann als unbenanntes Modul behandelt werden, indem im Klassenpfad mit -cp ein Nicht-Modul-Jar gesetzt wird

unnamed module -> named module

Ordnerstruktur


|-main/
| |-class/
| `-src/
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    |-module-info.java
    `-sample/sub/
      `-Sub.java

sub/src/module-info.java


module sample_module.sub {
    exports sample.sub;
}

Submodul kompilieren


#kompilieren
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

# jar 
> jar -c -f sub\jar\module-sub.jar -C sub\class .

Hauptmodul kompilieren


#kompilieren
> javac -p sub\jar\module-sub.jar --add-modules sample_module.sub -d main\class main\src\sample\main\Main.java

#Glas Kreation
> jar -c -f main\jar\no_module-main.jar -C main\class .

Lauf


> java -p sub\jar\module-sub.jar -cp main\jar\no_module-main.jar --add-modules sample_module.sub sample.main.Main
Sub.method()

unnamed module -> automatic module

Ordnerstruktur


|-main/
| |-class/
| `-src/
|   `-sample/main/
|     `-Main.java
|
`-sub/
  |-class/
  `-src/
    `-sample/sub/
      `-Sub.java

Submodul kompilieren


#kompilieren
> javac -d sub\class sub\src\sample\sub\Sub.java

#Glas Kreation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Hauptmodul kompilieren


#kompilieren
> javac -p sub\jar\no_module-sub.jar -d main\class --add-modules no.module.sub main\src\sample\main\Main.java

#Glas Kreation
> jar -c -f main\jar\no_module-main.jar -C main\class .

Lauf


> java -p sub\jar\no_module-sub.jar -cp main\jar\no_module-main.jar --add-modules no.module.sub sample.main.Main
Sub.method()

unnamed module -> unnamed module

Submodul kompilieren


#kompilieren
> javac -d sub\class sub\src\sample\sub\Sub.java

#Glas Kreation
> jar -c -f sub\jar\no_module-sub.jar -C sub\class .

Hauptmodul kompilieren


#kompilieren
> javac -d main\class -cp sub\jar\no_module-sub.jar main\src\sample\main\Main.java

#Glas Kreation
> jar -c -f main\jar\no_module-main.jar -C main\class .

Lauf


> java -cp sub\jar\no_module-sub.jar;main\jar\no_module-main.jar sample.main.Main
Sub.method()

――Dies ist im Grunde eine modulfreie Methode, dh sie befindet sich im selben Zustand wie das normale Kompilieren und Ausführen unter Java 8 oder weniger.

erfordert Modifikator

Einer der folgenden zwei Modifikatoren kann in "erfordert" eingestellt werden.

transitive

Modulabhängigkeiten


A -> B -> C

Angenommen, ein Modul B hängt von C ab. Es ist dieses "transitive" Qualifikationsmerkmal, das es "C" ermöglicht, automatisch "Anforderungen" zu stellen, wenn ein anderes Modul "A" "B" mit "Anforderungen" liest.

Erstens, wenn es kein Transitiv gibt

Ordnerstruktur


|-A/
| `-src/
|   |-module-info.java
|   `-a/
|     `-A.java
|-B/
| `-src/
|   |-module-info.java
|   `-b/
|     `-B.java
`-C/
  `-src/
    |-module-info.java
    `-c/
      `-C.java

** C-Modul **

C.java


package c;

public class C {}

C/src/module-info.java


module module_c {
    exports c;
}

** B-Modul **

B.java


package b;

import c.C;

public class B {}

B/src/module-info.java


module module_b {
    requires module_c;
    exports b;
}

** Ein Modul **

A.java


package a;

import b.B;
import c.C;

public class A {}

A/src/module-info.java


module module_a {
    requires module_b;
    // requires module_c;Versuchen Sie es ohne C-Modul
    exports a;
}

kompilieren

#C-Modul kompilieren
> javac -d c\class C\src\module-info.java C\src\c\C.java

#B-Modul kompilieren
> javac -p c\class -d b\class B\src\module-info.java B\src\b\B.java

#Ein Modul kompilieren
> javac -p c\class;b\class -d a\class A\src\module-info.java A\src\a\A.java
A\src\a\A.java:4:Error:Paket c kann nicht angezeigt werden
import c.C;
       ^
  (Paket c ist das Modulmodul_In c deklariert, aber Modulmodul_Nicht geladen in a)
1 Fehler

Das Paket "c" kann nicht referenziert werden, da das A-Modul das C-Modul nicht explizit benötigt.

Verwenden Sie transitiv

B\src\module-info.java


module module_b {
    requires transitive module_c;
    exports b;
}
#B-Modul kompilieren
> javac -p c\class -d b\class B\src\module-info.java B\src\b\B.java

#Ein Modul kompilieren
> javac -p c\class;b\class -d a\class A\src\module-info.java A\src\a\A.java

static Verwenden Sie "static" für Module, die "zur Kompilierungszeit erforderlich, zur Laufzeit jedoch optional" sind.

Wenn es keine statische Aufladung gibt

Ordnerstruktur


|-main/
| `-src/
|   |-module-info.java
|   `-sample/main/
|     |-SubFactory.java
|     `-Main.java
`-sub/
  `-src/
    |-module-info.java
    `-sample/sub/
      `-Sub.java

Sub.java


package sample.sub;

public class Sub {}

sub\src\module-info.java


module sample_module.sub {
    exports sample.sub;
}

SubFactory.java


package sample.main;

import sample.sub.Sub;

public class SubFactory {
    public static Sub newSub() {
        return new Sub();
    }
}

Main.java


package sample.main;

public class Main {
    public static void main(String... args) {
        System.out.println("Hello World!!");
    }
}

main/src/module-info.java


module sample_module.main {
    requires sample_module.sub;
}

Versuchen Sie zu kompilieren.

kompilieren


#Submodul kompilieren
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#Hauptmodul kompilieren
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java main\src\sample\main\SubFactory.java

Die Zusammenstellung besteht. Versuchen Sie es dann.

> java -p main\class -m sample_module.main/sample.main.Main
Error occurred during initialization of boot layer
java.lang.module.FindException: Module sample_module.sub not found, required by sample_module.main

Ein Fehler ist aufgetreten, weil das Submodul nicht gefunden wurde.

Wenn statisch hinzugefügt wird

main\src\module-info.java


module sample_module.main {
    requires static sample_module.sub;
}

Fügen Sie static hinzu und kompilieren Sie und führen Sie es auf die gleiche Weise aus.

#Hauptmodul kompilieren
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java main\src\sample\main\SubFactory.java

#Lauf
> java -p main\class -m sample_module.main/sample.main.Main
Hello World!!

Ich konnte es ausführen.

open Es kann nicht zur Kompilierungszeit referenziert werden, aber es kann so gesteuert werden, dass es zur Laufzeit referenziert werden kann. Dies wird verwendet, wenn Sie den Code mithilfe von Reflection referenzieren.

Es gibt zwei Typen, "opens", die für jedes Paket festgelegt sind, und "open module", die für das gesamte Modul festgelegt sind.

opens

Ordnerstruktur


|-main/
| `-src/
|   |-module-info.java
|   `-sample/main/
|     `-Main.java
`-sub/
  `-src/
    |-module-info.java
    `-sample/sub/
      `-Sub.java

Sub.java


package sample.sub;

public class Sub {
    public void sub() {
        System.out.println("Sub.sub()");
    }
}

sub\src\module-info.java


module sample_module.sub {
    //Erstellen Sie es zunächst, ohne es überhaupt zu veröffentlichen
}

Main.java


package sample.main;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Main {
    public static void main(String... args) throws Exception {
        Class<?> subClass = Class.forName("sample.sub.Sub");
        Constructor<?> constructor = subClass.getConstructor();
        Object sub = constructor.newInstance();

        Method method = subClass.getMethod("sub");
        method.invoke(sub);
    }
}

Auf das Paket "sample.sub" wird nicht direkt verwiesen, und die Methode "Sub.sub ()" wird unter Verwendung von Reflection ausgeführt.

main/src/module-info.java


module sample_module.main {
    requires sample_module.sub;
}

Versuchen Sie zu kompilieren.

#Submodul kompilieren
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#Hauptmodul kompilieren
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

sample.sub wird nicht statisch referenziert, daher wird es kompiliert. Aber wenn du das tust.

> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Exception in thread "main" java.lang.IllegalAccessException: class sample.main.Main (in module sample_module.main) cannot access class sample.sub.Sub (in module sample_module.sub) because module sample_module.sub does not export sample.sub to module sample_module.main
        at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
        at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:589)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:479)
        at sample_module.main/sample.main.Main.main(Main.java:10)

IllegalAccessException wird ausgelöst.

Veröffentlichen Sie sample.sub mit opens und versuchen Sie es erneut.

sub\src\module-info.java


module sample_module.sub {
    opens sample.sub;
}

Kompilieren und ausführen


#Submodul kompilieren
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java

#Hauptmodul kompilieren
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

#Lauf
> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Sub.sub()

Diesmal hat es gut funktioniert.

Übrigens, wenn Sie in diesem Zustand auf das sample.sub -Paket in Main.java verweisen (opens sample.sub;), ist dies wie folgt.

Main.java


package sample.main;

import sample.sub.Sub;

public class Main {
    public static void main(String... args) throws Exception {
        new Sub().sub();
    }
}

Normalerweise ist "Sub" "neu", um die Methode auszuführen.

kompilieren


#Hauptmodul kompilieren
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java
main\src\sample\main\Main.java:3:Error:Paketprobe.sub kann nicht angezeigt werden
import sample.sub.Sub;
             ^
  (Paketprobe.sub ist das Modulbeispiel_module.In Sub deklariert, aber nicht exportiert)
1 Fehler

Das Paket "sample.sub" wird nur "geöffnet", nicht "exportiert". Wenn Sie daher versuchen, beim Kompilieren statisch darauf zu verweisen, tritt ein Fehler auf.

Um die Verfügbarkeit der Referenz zu jedem Zeitpunkt zusammenzufassen,

Referenzzeitpunkt opens exports
Zur Kompilierungszeit ×
Laufzeit

So was.

open module opens ist eine Einstellung für ein bestimmtes Paket. Wenn Sie jedoch open module angeben, wird opens auf das gesamte Modul angewendet.

Ordnerstruktur


|-main/
| `-src/
|   |-module-info.java
|   `-sample/main/
|     `-Main.java
`-sub/
  `-src/
    |-module-info.java
    `-sample/sub/
      |-foo/
      | `-Foo.java
      `-Sub.java

Foo.java


package sample.sub.foo;

public class Foo {
    public void foo() {
        System.out.println("Foo.foo()");
    }
}

sub/src/module-info.java


open module sample_module.sub {
    exports sample.sub;
}

Main.java


package sample.main;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import sample.sub.Sub;

public class Main {
    public static void main(String... args) throws Exception {
        new Sub().sub();

        Class<?> clazz = Class.forName("sample.sub.foo.Foo");
        Constructor<?> constructor = clazz.getConstructor();
        Object obj = constructor.newInstance();

        Method method = clazz.getMethod("foo");
        method.invoke(obj);
    }
}

Kompilieren und ausführen


#Submodul kompilieren
> javac -d sub\class sub\src\module-info.java sub\src\sample\sub\Sub.java sub\src\sample\sub\foo\Foo.java

#Hauptmodul kompilieren
> javac -p sub\class -d main\class main\src\module-info.java main\src\sample\main\Main.java

#Lauf
> java -p sub\class;main\class -m sample_module.main/sample.main.Main
Sub.sub()
Foo.foo()

--sample.foo.Foo hat nicht opens oder export deklariert, kann aber aus der Reflexion referenziert werden.

use, provides ServiceLoader kann in module-info.java von Java 9 aus definiert werden.

Implementierung

Ordnerstruktur


|-user/
| `-src/
|   |-module-info.java
|   `-sample/user/
|     `-Main.java
|
`-provider/
  `-src/
    |-module-info.java
    `-sample/provider/
      |-api/
      | `-Foo.java
      `-impl/
        `-FooImpl.java

Foo.java


package sample.provider.api;

public interface Foo {
    void foo();
}

FooImpl.java


package sample.provider.impl;

import sample.provider.api.Foo;

public class FooImpl implements Foo {
    @Override
    public void foo() {
        System.out.println("FooImpl.foo()");
    }
}

provider/src/module-info.java


module sample_module.provider {
    exports sample.provider.api;
    provides sample.provider.api.Foo with sample.provider.impl.FooImpl;
}

Main.java


package sample.user;

import java.util.ServiceLoader;
import sample.provider.api.Foo;

public class Main {
    public static void main(String... args) {
        for (Foo foo : ServiceLoader.load(Foo.class)) {
            foo.foo();
        }
    }
}

user/src/module-info.java


module sample_module.user {
    requires sample_module.provider;
    uses sample.provider.api.Foo;
}

Funktionsprüfung

kompilieren


#Kompilieren des Provider-Moduls
> javac -d provider\class provider\src\module-info.java provider\src\sample\provider\api\Foo.java provider\src\sample\provider\impl\FooImpl.java

#Kompilieren des Benutzermoduls
> javac -d user\class -p provider\class user\src\module-info.java user\src\sample\user\Main.java

Lauf


> java -p provider\class;user\class -m sample_module.user/sample.user.Main
FooImpl.foo()

Erläuterung

provider/src/module-info.java


module sample_module.provider {
    exports sample.provider.api;
    provides sample.provider.api.Foo with sample.provider.impl.FooImpl;
}

user/src/module-info.java


module sample_module.user {
    requires sample_module.provider;
    uses sample.provider.api.Foo;
}

Es scheint, dass Sie sich bewusst sein sollten, dass es mehr Deklarationsmethoden gibt, beispielsweise beim Lesen des Codes des OSS-Frameworks.

[^ 1]: Klasse, die "Service" implementiert [^ 2]: Schnittstellen, abstrakte Klassen usw.

jlink Mit dem Befehl jlink können Sie eine Java-Laufzeit (Teilmenge) erstellen, die nur das Minimum an Modulen enthält. Auch wenn JRE nicht im Verteilungsziel installiert ist, können Sie die Anwendung starten, indem Sie die von jlink erstellte Teilmenge einschließen.

Implementierung

Ordnerstruktur


`-src/
  |-module-info.java
  `-sample/jlink/
    `-Main.java

Main.java


package sample.jlink;

public class Main {
    public static void main(String... args) {
        System.out.println("Hello jlink!!");
    }
}

module-info.java


module sample_module.jlink {
}

Erstellen Sie eine Teilmenge

#kompilieren
> javac -d class src\module-info.java src\sample\jlink\Main.java

#Glas Kreation
> jar -c -f jar\module-jlink.jar -C class .

#Erstellen Sie eine Laufzeit mit jlink
> jlink -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output

Die Anwendung mit Laufzeit wird wie unten gezeigt im Ordner "output" ausgegeben.

`-output/
  |-bin/
  |-conf/
  |-include/
  |-legal/
  |-lib/
  `-release

Unter "bin" befindet sich die Datei "java.exe", bei der es sich um den Befehl "java" für die Teilmenge handelt.

#Gehen Sie zum Teilmengenfach
> cd output\bin

#Überprüfen Sie die mitgelieferten Module
> java --list-modules
java.base@9
sample_module.jlink

Die Teilmenge enthält nur die minimal erforderlichen Module (java.base und sample_module.jlink).

Versuchen Sie, das Programm zu starten.

> java -m sample_module.jlink/sample.jlink.Main
Hello jlink!!

sample_module.jlink ist in die Laufzeit integriert, sodass Sie es nicht mit -p angeben müssen.

Die Größe der erstellten Laufzeit betrug übrigens 35,9 MB, als ich sie mit Windows Explorer überprüfte.

Kompresse

Kann optional bis zu einem gewissen Grad komprimiert werden.

> jlink --compress=2 -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output

--Komprimierung kann mit --compress = N angegeben werden.

-c, --compress=<0|1|2> Enable compression of resources:
                       Level 0: No compression
                       Level 1: Constant string sharing
                       Level 2: ZIP

Generieren Sie eine Startdatei

Die Notwendigkeit, die Hauptklasse beim Start mit "-m" anzugeben, ist nicht sehr gut, wenn sie an Personen verteilt wird, die mit Java nicht vertraut sind. In diesem Fall ist es praktisch, eine Skriptdatei für den Start zu generieren.

> jlink --launcher jlink-hello=sample_module.jlink/sample.jlink.Main  -p .\jar;%JAVA_HOME%\jmods --add-modules sample_module.jlink --output .\output
#Gehen Sie unter bin
> cd output\bin

#Führen Sie das Startskript aus
> jlink-hello.bat
Hello jlink!!

Die generierte Skriptdatei enthält den folgenden Inhalt.

jlink-hello.bat


@echo off
set JLINK_VM_OPTIONS=
set DIR=%~dp0
"%DIR%\java" %JLINK_VM_OPTIONS% -m sample_module.jlink/sample.jlink.Main %*

Das Shell-Skript für Linux wurde ebenfalls ausgegeben, aber kann es gestartet werden?

Untersuchen Sie abhängige Module

Mit dem Befehl jdeps können Sie herausfinden, von welchem Modul die JAR-Datei abhängt. Wenn Sie ein vorhandenes Nicht-Modul-JAR hinzufügen, wissen Sie, welches Modul in der Standardbibliothek hinzugefügt werden soll.

Schauen Sie sich als Test Apache Commons lang-3 an.

> jdeps -s commons-lang3-3.6.jar
commons-lang3-3.6.jar -> java.base
commons-lang3-3.6.jar -> java.desktop

Wenn Sie das Glas mit der Option "-s" füttern, werden die abhängigen Module angezeigt.

java.desktop ist ein Modul, das awt und Swing enthält, aber es gibt Beans und so weiter. Aha.

Wenn es sich bei der JAR um ein benanntes Modul handelt, müssen Sie das abhängige Modul mit "--module-path" angeben (natürlich ist es seltsam, ein abhängiges Modul zu haben, um das abhängige Modul nachzuschlagen. Machen).

Referenz

Recommended Posts

Puzzle-Studiennotizen
JavaFX-Studiennotizen
Docker-Studiennotizen
[Java] Studiennotizen
Puzzle-Notizen in Gradle
Mavens grundlegende Studiennotizen
Interne Studiennotizen im Klassen- und Lambda-Stil
JUnit 4 Notizen
Studienpolitik
Java Note
Anmerkungen zur Spring Framework-Studie [Teil 1] DI-Container
synchronisierte Notizen