当几个.java文件之间存在依赖关系时,我们是否需要按某种顺序编译它们?

问题描述 投票:-1回答:3

在编译几个.java文件时,它们之间有一些依赖关系,我们是否需要按某种顺序编译它们?

依赖项必须是.class文件吗?或者依赖项可以是.java文件吗?

具体来说,当A.java依赖于从B.java文件编译的B.class文件,但是B.class尚未创建(即B.java文件尚未编译成B.class),我们可以编译A. java通过在java -cp中指定B.java的目录?或者我们是否需要先将B.java编译成B.class,然后在编译A.java时在java -cp中指定B.class的目录?

例如,来自https://dzone.com/articles/java-8-how-to-create-executable-fatjar-without-ide./src/main/java/com/exec/one/Main.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

为什么以下编译成功?如何在一个javac命令中编译它们?如何在汇编中使用-cp ./src/main/java?编译过程中会发生什么?

$ javac -cp ./src/main/java ./src/main/java/com/exec/one/*.java ./src/main/java/com/exec/one/**/*.java

./双人床/卖弄/Java/com/exec/one/main.Java

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());                                                                                                                       

     }                                                                                                                                                                                  

}

./双人床/卖弄/Java/com/exec/one/service/magic service.Java

package com.exec.one.service;                                                                                                                                                          

public class MagicService {                                                                                                                                                            

  private final String message;                                                                                                                                                      

    public MagicService(){                                                                                                                                                             

        this.message = "Magic Message";                                                                                                                                                

    }                                                                                                                                                                                  

    public String getMessage(){                                                                                                                                                        

         return message;                                                                                                                                                                

    }                                                                                                                                                                                  

}
java javac
3个回答
3
投票

TL; DR如下所述,如果使用这个更简单的命令编译,只需要编译Main类,编译器仍然会找到并编译所需的MagicService类,因为它可以在类路径中找到源文件。

javac -cp ./src/main/java ./src/main/java/com/exec/one/Main.java

请参阅编译器文档页面的"Searching for Types" section

为了您的方便,请在此处引用所有内容,并添加了突出显示(粗体和/或斜体):

要编译源文件,编译器通常需要有关类型的信息,但类型定义不在命令行中指定的源文件中。编译器需要在源文件中使用,扩展或实现的每个类或接口的类型信息。这包括源文件中未明确提及但通过继承提供信息的类和接口。

例如,当您创建子类java.applet.Applet时,您还使用Applet的祖先类:java.awt.Paneljava.awt.Containerjava.awt.Componentjava.lang.Object

当编译器需要类型信息时,它会搜索定义类型的源文件或类文件。编译器首先在引导程序和扩展类中搜索类文件,然后在用户类路径(默认情况下是当前目录)中搜索。通过设置CLASSPATH环境变量或使用-classpath选项来定义用户类路径。

如果设置-sourcepath选项,则编译器会在指示的路径中搜索源文件。否则,编译器将在用户类路径中搜索类文件和源文件。

您可以使用-bootclasspath-extdirs选项指定不同的引导程序或扩展类。见Cross-Compilation Options

成功的类型搜索可以生成类文件,源文件或两者。如果两者都找到,那么您可以使用-Xprefer选项指示编译器使用哪个。如果指定了newer,则编译器将使用这两个文件中较新的文件。如果指定了source,则编译器使用源文件。默认值为newer

如果类型搜索单独找到所需类型的源文件,或者作为-Xprefer选项设置的结果,则编译器会读取源文件以获取所需的信息。默认情况下,编译器也会编译源文件。您可以使用-implicit选项指定行为。如果指定了none,则不会为源文件生成类文件。如果指定了class,则会为源文件生成类文件。

在注释处理完成之前,编译器可能不会发现某些类型信息的需要。如果在源文件中找到类型信息且未指定-implicit选项,则编译器会发出警告,指出正在编译该文件而不受注释处理的影响。要禁用警告,请在命令行上指定文件(以便进行注释处理)或使用-implicit选项指定是否应为此类源文件生成类文件。


2
投票

为什么以下编译失败?

$ javac ./src/main/java/com/exec/one/*.java -d ./out/

因为Main.java(在该命令中拾取的唯一文件)使用了一个名为com.exec.one.service.MagicService的类,该类在类路径中不可用,也不是正在编译的文件之一。

为什么以下编译成功?

$ javac -cp ./src/main/java ./src/main/java/com/exec/one/*.java ./src/main/java/com/exec/one/**/*.java

因为Main.java使用了一个名为com.exec.one.service.MagicService的类,它也是正在编译的文件之一。

如何在一个javac命令中编译它们?

你拥有的只是一个命令。 javac程序接受要编译的源文件列表

Usage: javac <options> <source files>

如何在汇编中使用-cp ./src/main/java

它用于设置类路径,即。它包括编译期间可能需要的类文件。在你的例子中,它没用。

但是,如果您已经单独编译了MagicService并将-cp指向相应的MagicServe.class文件所在的位置(考虑到与其包含的包匹配的目录结构),那么它将非常有用。这就是Java项目中包含第三方库的方式。


Java编译器不强加排序。简单地说,在编译时,所有必需的类必须是可用的,可以是通过编译的源文件,也可以是类路径中可用的类。


1
投票

看起来你应该从路径“/ src / main / java”开始。只有在您的文件夹名称下才能包含(com.exec.one)。所以做一个“cd src / main / java”并尝试:

javac ./com/exec/one/*.java
© www.soinside.com 2019 - 2024. All rights reserved.