web-dev-qa-db-fra.com

Temps de compilation vs dépendance d'exécution - Java

Quelle est la différence entre les dépendances de compilation et d'exécution en Java? Il est lié au chemin de classe, mais en quoi diffèrent-ils?

76
Kunal
  • Dépendance à la compilation: Vous avez besoin de la dépendance dans votre CLASSPATH pour compiler votre artefact. Ils sont produits parce que vous avez une sorte de "référence" à la dépendance codée en dur dans votre code, comme appeler new pour une classe, étendre ou implémenter quelque chose (directement ou indirectement), ou un appel de méthode utilisant le notation directe reference.method().

  • Dépendance au moment de l'exécution: Vous avez besoin de la dépendance dans votre CLASSPATH pour exécuter votre artefact. Ils sont produits parce que vous exécutez du code qui accède à la dépendance (soit de manière codée en dur, soit par réflexion ou autre).

Bien que la dépendance au moment de la compilation implique généralement une dépendance au moment de l'exécution, vous pouvez avoir une dépendance au moment de la compilation uniquement. Ceci est basé sur le fait que Java ne lie les dépendances de classe qu'au premier accès à cette classe, donc si vous n'accédez jamais à une classe particulière au moment de l'exécution car un chemin de code n'est jamais parcouru, Java ignorera à la fois la classe et ses dépendances.

Exemple de ceci

Dans C.Java (génère C.class):

package dependencies;
public class C { }

Dans A.Java (génère 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());
        }
    }
}

Dans ce cas, A a une dépendance au moment de la compilation sur C à B, mais il n'aura une dépendance au moment de l'exécution sur C que si vous transmettez certains paramètres lors de l'exécution Java dependencies.A, Car la JVM essaiera seulement de résoudre la dépendance de B sur C lorsqu'elle pourra exécuter B b = new B(). Cette fonctionnalité vous permet de fournir au moment de l'exécution uniquement les dépendances des classes que vous utilisez dans vos chemins de code et d'ignorer les dépendances des autres classes de l'artefact.

68
gpeche

Un exemple simple est de regarder une API comme l'API de servlet. Pour compiler vos servlets, vous avez besoin de servlet-api.jar, mais au moment de l'exécution, le conteneur de servlets fournit une implémentation api de servlet, vous n'avez donc pas besoin d'ajouter servlet-api.jar à votre chemin de classe d'exécution.

30
Martin Algesten

Le compilateur a besoin du bon chemin de classe pour compiler les appels à une bibliothèque (compiler les dépendances temporelles)

La machine virtuelle Java a besoin du chemin de classe approprié pour charger les classes dans la bibliothèque que vous appelez (dépendances d'exécution).

Ils peuvent être différents de deux manières:

1) si votre classe C1 appelle la classe de bibliothèque L1 et L1 appelle la classe de bibliothèque L2, alors C1 a une dépendance d'exécution sur L1 et L2, mais seulement une dépendance de temps de compilation sur L1.

2) si votre classe C1 instancie dynamiquement une interface I1 en utilisant Class.forName () ou un autre mécanisme, et que la classe d'implémentation de l'interface I1 est la classe L1, alors C1 a une dépendance d'exécution sur I1 et L1, mais seulement une dépendance de temps de compilation sur I1.

Autres dépendances "indirectes" identiques pour la compilation et l'exécution:

3) votre classe C1 étend la classe de bibliothèque L1, et L1 implémente l'interface I1 et étend la classe de bibliothèque L2: C1 a une dépendance au moment de la compilation sur L1, L2 et I1.

4) votre classe C1 a une méthode foo(I1 i1) et une méthode bar(L1 l1) où I1 est une interface et L1 est une classe qui prend un paramètre qui est l'interface I1: C1 a un temps de compilation dépendance à I1 et L1.

Fondamentalement, pour faire quelque chose d'intéressant, votre classe doit s'interfacer avec d'autres classes et interfaces dans le chemin de classe. Le graphe classe/interface formé par cet ensemble de bibliothèque interfaces renvoie la chaîne de dépendances au moment de la compilation. Les implémentations de la bibliothèque produisent la chaîne de dépendances au moment de l'exécution. Notez que le la chaîne de dépendance temporelle dépend de l'exécution ou échoue: si l'implémentation de L1 dépend parfois de l'instanciation d'un objet de classe L2, et que cette classe n'est instanciée que dans un scénario particulier, il n'y a pas de dépendance sauf dans ce scénario.

25
Jason S

Java ne lie en fait rien au moment de la compilation. Il vérifie uniquement la syntaxe à l'aide des classes correspondantes trouvées dans CLASSPATH. Ce n'est qu'au moment de l'exécution que tout est assemblé et exécuté sur la base du CLASSPATH à ce moment-là.

11
JOTN

Les dépendances de temps de compilation ne sont que les dépendances (autres classes) que vous utilisez directement dans la classe que vous compilez. Les dépendances d'exécution couvrent les dépendances directes et indirectes de la classe que vous exécutez. Ainsi, les dépendances d'exécution incluent les dépendances des dépendances et toutes les dépendances de réflexion comme les noms de classe que vous avez dans un String, mais qui sont utilisées dans Class#forName().

10
BalusC

Pour Java, la dépendance de temps de compilation est la dépendance de votre code source. Par exemple, si la classe A appelle une méthode de la classe B, alors A dépend de B au moment de la compilation, car A doit connaître B (type de B) à compiler. L'astuce ici devrait être la suivante: le code compilé n'est pas encore un code complet et exécutable. Il comprend des adresses remplaçables (symboles, métadonnées) pour les sources qui ne sont pas encore compilées ou qui existent dans des fichiers jars externes. Lors de la liaison, ces adresses doivent être remplacées par des adresses réelles en mémoire. Pour le faire correctement, des symboles/adresses corrects doivent être créés. Et cela peut être fait avec le type de la classe (B). Je crois que c'est la principale dépendance au moment de la compilation.

La dépendance à l'exécution est davantage liée au flux de contrôle réel. Il invoque les adresses mémoire réelles. C'est une dépendance que vous avez lorsque votre programme est en cours d'exécution. Vous avez besoin ici de détails de classe B comme les implémentations, pas seulement les informations de type. Si la classe n'existe pas, vous obtiendrez RuntimeException et JVM se fermera.

Les deux dépendances, généralement et ne devraient pas, vont dans le même sens. C'est une question de conception OO cependant.

En C++, la compilation est un peu différente (pas juste à temps) mais elle a aussi un éditeur de liens. Ainsi, le processus pourrait être considéré comme similaire à Java je suppose.

1
stdout