Antworten:
Compile-Zeitabhängigkeit : Sie müssen die Abhängigkeit in Ihrem CLASSPATH
Ihren Artefakt zu kompilieren. Sie werden erzeugt, weil Sie eine Art "Verweis" auf die in Ihrem Code fest codierte Abhängigkeit haben, z. B. das Aufrufen new
einer Klasse, das Erweitern oder Implementieren von etwas (entweder direkt oder indirekt) oder einen Methodenaufruf unter Verwendung der direkten reference.method()
Notation.
Laufzeitabhängigkeit : Sie benötigen die Abhängigkeit in Ihrem CLASSPATH
, um Ihr Artefakt auszuführen. Sie werden erzeugt, weil Sie Code ausführen, der auf die Abhängigkeit zugreift (entweder fest codiert oder durch Reflektion oder was auch immer).
Obwohl die Abhängigkeit zur Kompilierungszeit normalerweise eine Laufzeitabhängigkeit impliziert, können Sie nur eine Abhängigkeit zur Kompilierungszeit haben. Dies basiert auf der Tatsache, dass Java Klassenabhängigkeiten nur 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, ignoriert Java sowohl die Klasse als auch ihre Abhängigkeiten.
Beispiel dafür
In C.java (erzeugt C.class):
package dependencies;
public class C { }
In A.java (erzeugt 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 A
besteht eine Abhängigkeit von der Kompilierungszeit von C
bis B
, aber nur eine Laufzeitabhängigkeit von C, wenn Sie bei der Ausführung einige Parameter übergeben java dependencies.A
, da die JVM nur versucht, die B
Abhängigkeit von C
der Ausführung zu lösen , wenn sie ausgeführt werden soll B b = new B()
. 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.
Ein einfaches Beispiel ist das Betrachten einer API wie der Servlet-API. Damit Ihre Servlets kompiliert werden können, benötigen Sie die Datei servlet-api.jar. Zur Laufzeit bietet der Servlet-Container jedoch eine Servlet-API-Implementierung, sodass Sie servlet-api.jar nicht zu Ihrem Laufzeitklassenpfad hinzufügen müssen.
Der Compiler benötigt den richtigen Klassenpfad, um Aufrufe an eine Bibliothek zu kompilieren (Abhängigkeiten zur Kompilierungszeit).
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 Kompilierungszeitabhängigkeit 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 die Kompilierungs- und Laufzeit gleich sind:
3) Ihre Klasse C1 erweitert die Bibliotheksklasse L1, und L1 implementiert die Schnittstelle I1 und erweitert die Bibliotheksklasse L2: C1 ist zur Kompilierungszeit von L1, L2 und I1 abhängig.
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 Abhängigkeit zur Kompilierungszeit von I1 und L1.
Grundsätzlich muss Ihre Klasse mit anderen Klassen und Schnittstellen im Klassenpfad kommunizieren, um etwas Interessantes zu tun. Die Klasse / Schnittstellen Graph , der durch diesen Satz von Bibliothek gebildet Schnittstellen ergibt die Kompilierung-Abhängigkeitskette. Die Bibliothek Implementierungen ergeben die Laufzeitabhängigkeitskette. Beachten Sie, dass die Laufzeitabhängigkeitskette zur Laufzeit abhängig oder ausfallsicher ist: Wenn die Implementierung von L1 manchmal von der Instanziierung eines Objekts der Klasse L2 abhängt und diese Klasse nur in einem bestimmten Szenario instanziiert wird, gibt es keine Abhängigkeit außer in dieses Szenario.
Java verknüpft zur Kompilierungszeit eigentlich nichts. Die Syntax wird nur anhand der übereinstimmenden Klassen überprüft, die im CLASSPATH gefunden werden. Erst zur Laufzeit wird alles basierend auf dem CLASSPATH zu diesem Zeitpunkt zusammengestellt und ausgeführt.
Kompilierzeitabhängigkeiten sind nur die Abhängigkeiten (andere Klassen), die Sie direkt in der Klasse verwenden, die Sie kompilieren. Laufzeitabhängigkeiten decken sowohl die direkten als auch die indirekten Abhängigkeiten der Klasse ab, die Sie ausführen. Daher umfassen Laufzeitabhängigkeiten Abhängigkeiten von Abhängigkeiten und alle Reflexionsabhängigkeiten wie Klassennamen, die Sie in a haben, in denen Sie String
jedoch verwendet werden Class#forName()
.
A
, B.jar mit B extends A
und C.jar mit haben, C extends B
dann hängt C.jar von der Kompilierungszeit von A.jar ab, obwohl die C-Abhängigkeit von A indirekt ist.
Für Java ist die Abhängigkeit von der Kompilierungszeit die Abhängigkeit Ihres Quellcodes. Wenn Klasse A beispielsweise eine Methode aus Klasse B aufruft, ist A zur Kompilierungszeit von B abhängig, da A über B (Typ von B) Bescheid wissen muss, um kompiliert zu werden. Der Trick hier sollte folgender sein: Kompilierter Code ist noch kein vollständiger und ausführbarer Code. Es enthält austauschbare 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 beim Kompilieren.
Die Laufzeitabhängigkeit hängt eher mit dem tatsächlichen Kontrollfluss zusammen. Es handelt sich um tatsächliche Speicheradressen. Es ist eine Abhängigkeit, die Sie haben, wenn Ihr Programm ausgeführt wird. Sie benötigen hier Details der Klasse B wie Implementierungen, nicht nur die Typinformationen. Wenn die Klasse nicht vorhanden ist, erhalten Sie RuntimeException und JVM wird beendet.
Beide Abhängigkeiten fließen im Allgemeinen und sollten nicht in die gleiche Richtung. Dies ist jedoch eine Frage des OO-Designs.
In C ++ ist die Kompilierung etwas anders (nicht nur in der Zeit), aber es gibt auch einen Linker. Der Prozess könnte also ähnlich wie Java sein, denke ich.