Lors de la compilation de plusieurs fichiers .java avec une relation de dépendance entre eux, devons-nous les compiler dans un certain ordre?
Une dépendance doit-elle être un fichier .class? Ou une dépendance peut-elle être un fichier .java?
Plus précisément, lorsque A.java dépend du fichier B.class compilé à partir du fichier B.java, mais que B.class n'a pas été créé (c'est-à-dire B.java n'a pas été compilé dans B.class), pouvons-nous compiler A.java en spécifiant le répertoire de B.java dans java -cp
? Ou devons-nous d'abord compiler B.java dans B.class, puis spécifier le répertoire de B.class dans java -cp
lors de la compilation de A.java?
Par exemple , depuis https://dzone.com/ articles / java-8-comment-créer-exécutable-fatjar-sans-ide , ./src/main/java/com/exec/one/Main.java
dépend de ./src/main/java/com/exec/one/service/MagicService.java
, et les deux n'ont pas encore été compilés.
Pourquoi la compilation suivante échoue-t-elle?
package com.exec.one.service; public class MagicService { private final String message; public MagicService(){ this.message = "Magic Message"; } public String getMessage(){ return message; } }
Pourquoi la compilation suivante réussit-elle? Comment les compiler en une seule commande javac
? Comment -cp ./src/main/java
est-il utilisé dans la compilation? Que se passe-t-il lors du processus de compilation?
package com.exec.one; import com.exec.one.service.MagicService; public class Main { public static void main(String[] args){ System.out.println("Main Class Start"); MagicService service = new MagicService(); System.out.println("MESSAGE : " + service.getMessage()); } }
./src/main/java/com/exec/one/Main.java
$ javac -cp ./src/main/java ./src/main/java/com/exec/one/*.java ./src/main/java/com/exec/one/**/*.java
./src/main/java/com/exec/one/service/MagicService.java
$ javac ./src/main/java/com/exec/one/*.java -d ./out/ ./src/main/java/com/exec/one/Main.java:3: error: package com.exec.one.service does not exist import com.exec.one.service.MagicService; ^ ./src/main/java/com/exec/one/Main.java:8: error: cannot find symbol MagicService service = new MagicService(); ^ symbol: class MagicService location: class Main ./src/main/java/com/exec/one/Main.java:8: error: cannot find symbol MagicService service = new MagicService(); ^ symbol: class MagicService location: class Main 3 errors
3 Réponses :
Il semble que vous devriez commencer à l'intérieur du chemin "/ src / main / java". Seulement en dessous, vous avez des packages (com.exec.one) correspondant aux noms de vos dossiers. Alors faites un "cd src / main / java" et essayez:
javac ./com/exec/one/*.java
Pourquoi la compilation suivante échoue-t-elle?
Usage: javac <options> <source files>Parce que
Main.java
(le seul fichier sélectionné dans cette commande) utilise une classe appeléecom.exec.one.service.MagicService
qui n'est pas disponible sur le chemin de classe ni l'un des fichiers en cours de compilation.Pourquoi la compilation suivante réussit-elle?
$ javac -cp ./src/main/java ./src/main/java/com/exec/one/*.java ./src/main/java/com/exec/one/**/*.javaParce que
Main.java
utilise une classe appeléecom.exec.one.service.MagicService
qui est également l'un des fichiers en cours de compilation.Comment les compiler en une seule commande
javac
?Ce que vous avez est déjà une commande. Le programme
javac
accepte une liste de fichiers source à compiler$ javac ./src/main/java/com/exec/one/*.java -d ./out/Comment
-cp ./src/main/java
est-il utilisé dans la compilation?Il est utilisé pour définir le chemin de classe, c'est-à-dire. il inclut les fichiers de classe qui peuvent être nécessaires lors de la compilation. Dans votre exemple, cela ne sert à rien.
Cependant, si vous aviez compilé
MagicService
séparément et pointé le-cp
partout où leMagicServe correspondant. class
a été localisé (en tenant compte de la structure de répertoire qui correspond à son paquet contenant), cela aurait été utile. C'est ainsi que les bibliothèques tierces sont incluses dans les projets Java.
Le compilateur Java n'impose pas de classement. Simplement, au moment de la compilation, toutes les classes requises doivent être disponibles, soit via un fichier source en cours de compilation, soit via une classe disponible dans le chemin des classes.
Votes à la hausse même si vous n'êtes pas tout à fait correct (voir ma réponse ). Les fichiers sources peuvent être compilés même s'ils ne sont pas répertoriés dans la commande, tant que le fichier source se trouve sur le sourcepath
(ou classpath
s'il n'y a pas de sourcepath code> est donné).
TL; DR Comme indiqué ci-dessous, si vous compilez avec cette commande plus simple, où vous demandez uniquement de compiler la classe Main
, le compilateur localisera et compilera toujours le requise la classe MagicService
, car elle peut trouver le fichier source sur le chemin de classe.
javac -cp ./src/main/java ./src/main/java/com/exec/one/Main.java
Voir le Section" Recherche de types " de la page de documentation du compilateur.
Tout citer ici pour votre commodité, avec des surlignages ( gras et / ou italique ) ajoutés par moi:
Pour compiler un fichier source, le compilateur a souvent besoin d'informations sur un type, mais la définition de type ne se trouve pas dans les fichiers source spécifiés sur la ligne de commande. Le compilateur a besoin d'informations de type pour chaque classe ou interface utilisée, étendue ou implémentée dans le fichier source. Cela inclut les classes et les interfaces qui ne sont pas explicitement mentionnées dans le fichier source, mais qui fournissent des informations par héritage.
Par exemple, lorsque vous créez une sous-classe
java.applet.Applet
, vous utilisez également les classes ancêtres de l'Applet:java.awt.Panel
,java.awt.Container
,java.awt.Component
etjava.lang.Object
.Lorsque le compilateur a besoin d'informations de type, il recherche un fichier source ou un fichier classe qui définit le type. Le compilateur recherche d'abord les fichiers class dans les classes d'amorçage et d'extension, puis dans le chemin de la classe utilisateur (qui par défaut est le répertoire courant). Le chemin de la classe utilisateur est défini en définissant la variable d'environnement
CLASSPATH
ou en utilisant l'option-classpath
.Si vous définissez l'option
-sourcepath
, alors le compilateur recherche le chemin indiqué pour les fichiers source. Sinon, le compilateur recherche le chemin de la classe utilisateur pour les fichiers class et source .Vous pouvez spécifier différentes classes d'amorçage ou d'extension avec les options
-bootclasspath
et-extdirs
. Voir Options de compilation croisée .Une recherche de type réussie peut produire un fichier de classe, un fichier source ou les deux. Si les deux sont trouvés, vous pouvez utiliser l'option
-Xprefer
pour indiquer au compilateur lequel utiliser. Sinewer
est spécifié, alors le compilateur utilise le plus récent des deux fichiers. Sisource
est spécifié, le compilateur utilise le fichier source. La valeur par défaut estnewer
.Si une recherche de type trouve un fichier source pour un type requis, soit seul, soit à la suite du paramètre de
-Xprefer code>, puis le compilateur lit le fichier source pour obtenir les informations dont il a besoin. Par défaut, le compilateur compile également le fichier source. Vous pouvez utiliser l'option
-implicit
pour spécifier le comportement. Sinone
est spécifié, aucun fichier de classe n'est généré pour le fichier source. Siclass
est spécifié, les fichiers de classe sont générés pour le fichier source.Le compilateur peut ne pas découvrir la nécessité de certaines informations de type avant la fin du traitement des annotations. Lorsque les informations de type sont trouvées dans un fichier source et qu'aucune option
-implicit
n'est spécifiée, le compilateur donne un avertissement que le fichier est en cours de compilation sans être soumis au traitement des annotations. Pour désactiver l'avertissement, spécifiez le fichier sur la ligne de commande (afin qu'il soit soumis au traitement des annotations) ou utilisez l'option-implicit
pour spécifier si les fichiers de classe doivent ou non être générés pour cette source fichiers.
Notez que c'est le comportement du compilateur Oracle et que cela peut ne pas être le même pour les autres implémentations du compilateur.
Merci. J'utilise openjdk
Est-ce un projet maven?
@ ThorbjørnRavnAndersen Ce n'est pas le cas.