webentwicklung-frage-antwort-db.com.de

Kompilierzeit vs. Laufzeitabhängigkeit - Java

Was ist der Unterschied zwischen der Kompilierungszeit und den Laufzeitabhängigkeiten in Java? Es hängt mit dem Klassenpfad zusammen, aber wie unterscheiden sie sich?

76
Kunal
  • Kompilierzeitabhängigkeit: Sie benötigen die Abhängigkeit in Ihrer CLASSPATH, um Ihr Artefakt zu kompilieren. Sie werden erzeugt, weil Sie eine Art "Referenz" auf die in Ihrem Code fest codierte Abhängigkeit haben, z. B. den Aufruf von new für eine Klasse, das Erweitern oder Implementieren von etwas (entweder direkt oder indirekt) oder einen Methodenaufruf unter Verwendung von direkte reference.method() Notation.

  • Laufzeitabhängigkeit: Sie benötigen die Abhängigkeit in Ihrem CLASSPATH, um Ihr Artefakt auszuführen. Sie entstehen, weil Sie Code ausführen, der auf die Abhängigkeit zugreift (entweder in fester Codierung oder über Reflektion oder was auch immer).

Obwohl die Abhängigkeit von der Kompilierungszeit normalerweise Laufzeitabhängigkeiten impliziert, können Sie eine Abhängigkeit nur von der Kompilierungszeit haben. Dies basiert auf der Tatsache, dass Java nur Klassenabhängigkeiten beim ersten Zugriff auf diese Klasse verknüpft. Wenn Sie also zur Laufzeit nie auf eine bestimmte Klasse zugreifen, weil ein Codepfad nie durchlaufen wird, Java ignoriert sowohl die Klasse als auch ihre Abhängigkeiten.

Beispiel dafür

In C.Java (generiert C.class):

package dependencies;
public class C { }

In A.Java (generiert A.class):

package dependencies;
public class A {
    public static class B {
        public String toString() {
            C c = new C();
            return c.toString();
        }
    }
    public static void main(String[] args) {
        if (args.length > 0) {
            B b = new B();
            System.out.println(b.toString());
        }
    }
}

In diesem Fall hat A eine Kompilierungszeitabhängigkeit von C bis B, aber nur dann eine Laufzeitabhängigkeit von C, wenn Sie beim Ausführen einige Parameter übergeben Java dependencies.A, Da die JVM nur versucht, die Abhängigkeit von B von C zu lösen, wenn sie B b = new B() ausführt. Mit dieser Funktion können Sie zur Laufzeit nur die Abhängigkeiten der Klassen bereitstellen, die Sie in Ihren Codepfaden verwenden, und die Abhängigkeiten der übrigen Klassen im Artefakt ignorieren.

68
gpeche

Ein einfaches Beispiel ist, eine API wie die Servlet-API zu betrachten. Damit Ihre Servlets kompiliert werden können, benötigen Sie die Datei servlet-api.jar. Zur Laufzeit stellt der Servlet-Container jedoch eine Servlet-API-Implementierung bereit, sodass Sie der Laufzeitklasse servlet-api.jar nicht hinzufügen müssen.

30
Martin Algesten

Der Compiler benötigt den richtigen Klassenpfad, um Aufrufe an eine Bibliothek zu kompilieren (Kompilierzeitabhängigkeiten)

Die JVM benötigt den richtigen Klassenpfad, um die Klassen in die aufgerufene Bibliothek zu laden (Laufzeitabhängigkeiten).

Sie können in vielerlei Hinsicht unterschiedlich sein:

1) Wenn Ihre Klasse C1 die Bibliotheksklasse L1 und L1 die Bibliotheksklasse L2 aufruft, hat C1 eine Laufzeitabhängigkeit von L1 und L2, aber nur eine Abhängigkeit der Kompilierzeit von L1.

2) Wenn Ihre Klasse C1 eine Schnittstelle I1 mithilfe von Class.forName () oder einem anderen Mechanismus dynamisch instanziiert und die implementierende Klasse für die Schnittstelle I1 die Klasse L1 ist, hat C1 eine Laufzeitabhängigkeit von I1 und L1, jedoch nur eine Abhängigkeit von der Kompilierungszeit auf I1.

Andere "indirekte" Abhängigkeiten, die für Kompilierungszeit und Laufzeit gleich sind:

3) Ihre Klasse C1 erweitert die Bibliotheksklasse L1, und L1 implementiert die Schnittstelle I1 und erweitert die Bibliotheksklasse L2: C1 hat eine Abhängigkeit zur Kompilierungszeit von L1, L2 und I1.

4) Ihre Klasse C1 hat eine Methode foo(I1 i1) und eine Methode bar(L1 l1), wobei I1 eine Schnittstelle ist und L1 eine Klasse ist, die einen Parameter annimmt, der Schnittstelle I1 ist: C1 hat eine Kompilierungszeit Abhängigkeit von I1 und L1.

Grundsätzlich muss Ihre Klasse eine Schnittstelle zu anderen Klassen und Schnittstellen im Klassenpfad haben, um etwas Interessantes zu tun. Das von dieser Gruppe von Bibliotheksschnittstellen gebildete Klassen-/Schnittstellen-Diagramm liefert die Abhängigkeitskette zur Kompilierungszeit. Die Bibliotheksimplementierungen ergeben die Laufzeit-Abhängigkeitskette. Beachten Sie, dass die Laufzeit-Abhängigkeitskette laufzeitabhängig oder ausfallsicher ist: wenn die Implementierung von L1 hängt manchmal von der Instanziierung eines Objekts der Klasse L2 ab, und diese Klasse wird nur in einem bestimmten Szenario instanziiert. Dann gibt es keine Abhängigkeit außer in diesem Szenario.

25
Jason S

Java verknüpft zur Kompilierungszeit eigentlich nichts. Die Syntax wird nur anhand der übereinstimmenden Klassen überprüft, die in CLASSPATH enthalten sind. Erst zur Laufzeit wird alles basierend auf dem CLASSPATH zu diesem Zeitpunkt zusammengestellt und ausgeführt.

11
JOTN

Compiletime-Abhängigkeiten sind nur die Abhängigkeiten (andere Klassen), die Sie direkt in der Klasse verwenden, die Sie kompilieren. Laufzeitabhängigkeiten umfassen sowohl die direkten als auch die indirekten Abhängigkeiten der von Ihnen ausgeführten Klasse. Daher umfassen Laufzeitabhängigkeiten Abhängigkeiten von Abhängigkeiten und alle Reflektionsabhängigkeiten wie Klassennamen, die Sie in einem String haben, die jedoch in Class#forName() verwendet werden.

10
BalusC

Bei Java ist die Kompilierungszeitabhängigkeit die Abhängigkeit Ihres Quellcodes. Wenn beispielsweise Klasse A eine Methode aus Klasse B aufruft, ist A zum Kompilierungszeitpunkt von B abhängig, da A über B (Typ von B) Bescheid wissen muss, das kompiliert werden soll. Der Trick sollte hier sein: Kompilierter Code ist noch kein vollständiger und ausführbarer Code. Es enthält ersetzbare Adressen (Symbole, Metadaten) für die Quellen, die noch nicht kompiliert wurden oder in externen Gläsern vorhanden sind. Während der Verknüpfung müssen diese Adressen durch tatsächliche Adressen im Speicher ersetzt werden. Um dies richtig zu machen, sollten korrekte Symbole/Adressen erstellt werden. Und dies kann mit dem Typ der Klasse (B) erfolgen. Ich glaube, das ist die Hauptabhängigkeit zum Zeitpunkt der Kompilierung.

Die Laufzeitabhängigkeit hängt mehr mit dem tatsächlichen Steuerungsfluss zusammen. Es erfasst die tatsächlichen Speicheradressen. Es ist eine Abhängigkeit, die Sie haben, wenn Ihr Programm ausgeführt wird. Sie benötigen hier Klasse-B-Details wie Implementierungen, nicht nur die Typinformationen. Wenn die Klasse nicht existiert, erhalten Sie RuntimeException und JVM wird beendet.

Beide Abhängigkeiten fließen im Allgemeinen und sollten nicht in dieselbe Richtung. Dies ist jedoch eine Frage des OO Designs.

In C++ ist die Kompilierung etwas anders (nicht just in time), aber es gibt auch einen Linker. Also könnte der Prozess ähnlich gedacht werden wie Java Ich denke.

1
stdout