2
votes

Lorsqu'il existe une dépendance entre plusieurs fichiers .java, devons-nous les compiler dans un certain ordre?

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


2 commentaires

Est-ce un projet maven?


@ ThorbjørnRavnAndersen Ce n'est pas le cas.


3 Réponses :


1
votes

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


0 commentaires

3
votes

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ée com.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/**/*.java

Parce que Main.java utilise une classe appelée com.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ù le MagicServe 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.


1 commentaires

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 est donné).



3
votes

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 et java.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. Si newer est spécifié, alors le compilateur utilise le plus récent des deux fichiers. Si source est spécifié, le compilateur utilise le fichier source. La valeur par défaut est newer .

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. Si none est spécifié, aucun fichier de classe n'est généré pour le fichier source. Si class 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.


2 commentaires

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