Javac - 编译器

您可以使用基础的JDK工具和命令来创建和构建应用程序。以下部分描述了可以用来创建和构建应用程序的工具和命令:

介绍 javac

javac - 读取Java类和接口定义,并将它们编译成字节码和类文件

javac [options] [sourcefiles]

options 命令行选项。

sourcefiles 要编译的一个或多个源文件(如 MyClass.java)或为注释处理的源文件(如MyPackage.MyClass)。

描述

javac命令读取用Java编程语言编写的类和接口定义,并将它们编译成字节码类文件。javac命令还可以处理Java源文件和类中的注释。

JDK 9中引入了一个启动器环境变量JDK_JAVAC_OPTIONS,它将其内容附加到javac的命令行中。

有两种方法可以将源代码文件名传递给javac:

  • 对于一些源文件,您可以在命令行中列出文件名。
  • 对于一些源文件,您可以使用javac命令行上的@filename选项来包含一个列出源文件名的文件。

例如,一个名为MyClass的类将被写入名为MyClass.java的源文件中:

class MyClass {
    public static void main(String[] args) {
        System.out.println("this is my class");
    }
}

并编译成一个名为MyClass.class的字节码类文件:

javac MyClass.java

MyClass.java
MyClass.class

内部类定义产生额外的类文件。这些类文件的名称结合了内部和外部类的名称,如MyClass$MyInnerClass.class。

您应该将源文件放在反映其包树的目录树中。例如:

  • Linux和macOS:如果你所有的源文件都在/workspace中,那么把com.mysoft.mypack.MyClass的源代码放在/workspace/com/mysoft/mypack/MyClass.java中。
  • Windows:如果你所有的源文件都在\workspace中,那么把com.mysoft.mypack. MyClass 的源代码放在\workspace\com\mysoft\mypack\MyClass.java中。

默认情况下,编译器将每个类文件放在与其源文件相同的目录中。您可以使用Standard Options中描述的-d选项指定一个单独的目标目录。

接口编程

javac命令支持 javax.tools package中的类和接口定义的新的Java Compiler API
隐式加载源文件
要编译一组源文件,编译器可能需要隐式加载额外的源文件。这些文件目前不受注释处理的约束。默认情况下,当注释处理发生并且编译任何隐式加载的源文件时,编译器会发出警告。隐式选项提供了一种抑制警告的方法。
使用JDK_JAVAC_OPTIONS环境变量

JDK_JAVAC_OPTIONS环境变量的内容,由空格或空白字符(\n、\t、\r或\f)分隔,作为参数列表被附加到传递给javac的命令行参数之前。

环境变量的编码要求与系统上的javac命令行相同。JDK_JAVAC_OPTIONS环境变量内容的处理方式与命令行中指定的方式相同。

单引号或双引号可以用来包围包含空白字符的参数。只要删除这对引号,就可以保留左引号和第一个匹配的右引号之间的所有内容。如果没有找到匹配的quote,启动程序将中止并返回错误消息。支持@files,因为它们是在命令行中指定的。但是,和@files一样,不支持使用通配符:

export JDK_JAVAC_OPTIONS='@"C:\white spaces\argfile"'

export JDK_JAVAC_OPTIONS='"@C:\white spaces\argfile"'

export JDK_JAVAC_OPTIONS='@C:\"white spaces"\argfile'

javac Options概述

编译器有一组标准选项和当前开发环境支持的交叉编译选项。编译器还有一组非标准选项,这些选项是特定于当前虚拟机和编译器实现的,但在未来可能会发生变化。非标准选项以-X开头。不同的javac选项集将在下面的章节中描述:

  • 标准的选项
  • javac的交叉编译选项
  • 额外的选项
标准的Options

@filename读取文件选项和文件名。要缩短或简化javac命令,可以指定一个或多个包含javac命令参数的文件(-J选项除外)。这允许您在任何操作系统上创建任意长度的javac命令。

  • -Akey[=value]指定要传递给注释处理器的选项。这些选项不是javac直接解释的,而是供各个处理器使用的。键值应该是一个或多个由点分隔的标识符。
  • –add-modules module,module指定要解析的根模块和初始模块,如果module是all -module - path,则指定模块路径上的所有模块。
  • –boot-class-path path或-bootclasspath path覆盖引导类文件的位置。
    –class-path path、-classpath path或-cp path指定在何处查找用户类文件和注释处理器。这个类路径覆盖CLASSPATH环境变量中的用户类路径:
  • 如果没有指定–class-path、-classpath或-cp,则用户类路径为当前目录。
  • 如果未指定-sourcepath选项,则还将搜索用户类路径以查找源文件。
  • 如果没有指定-processorpath选项,则类路径也将搜索注释处理器。

-d directory设置类文件的目标目录。如果类是包的一部分,那么javac将类文件放在反映包名的子目录中,并根据需要创建目录。

  • Linux和macOS:如果指定-d /home/myclasses,并且类名为com.mypackage.MyClass,然后类文件是/home/myclasses/com/mypackage/MyClass.class。
  • Windows:如果你指定-d C:\myclasses,并且类名为com.mypackage.MyClass,那么类文件就是C: myclasses\com\mypackage\MyClass.class。

-deprecation 显示已弃用成员或类的每次使用或重写的描述。如果没有-deprecation选项,javac将显示使用或覆盖已弃用成员或类的源文件的摘要。-deprecation选项是-Xlint:deprecation的简写。

–enable-preview 启用语言预览功能。与-source或-release一起使用。

-encoding encoding 源文件使用的字符编码,如EUC-JP、UTF-8。如果没有指定-encoding选项,则使用平台默认编码。
-endorseddirs directories 覆盖指定标准路径的位置。

-extdirs directories 覆盖已安装扩展的位置。directories变量是一个用冒号分隔的目录列表。在指定目录中的每个JAR文件中搜索类文件。所有找到的JAR文件都成为类路径的一部分。

-g 生成所有调试信息,包括本地变量。缺省情况下,只生成行号和源文件信息。

-g:[lines, vars, source] 只生成由逗号分隔的关键字列表指定的调试信息。有效的关键词是:

’ lines ’ -行号调试信息。

’ vars ’ -本地变量调试信息。

’ source ’ -源文件调试信息。
-g:none不生成调试信息。

-h directory 指定本地头文件的存放位置。
当您指定此选项时,将为每个包含本机方法或具有一个或多个用java.lang.annotation.Native annotation注释的常量的类生成一个本机头文件。如果类是包的一部分,那么编译器将本机头文件放在反映包名的子目录中,并根据需要创建目录。

–help,-help还是-? 打印标准选项的概要。

–help-extra或-X 打印额外选项的帮助。

-implicit:[none, class] 是否为隐式引用的文件生成类文件:

-implicit:class 自动生成类文件。

-implicit:none 禁止生成类文件。

如果未指定此选项,则默认会自动生成类文件。在这种情况下,如果在进行注释处理时生成了任何类文件,编译器就会发出警告。当显式设置-implicit选项时,不会发出警告。参见搜索类型。
-Joption 将选项传递到运行时系统,选项是Java命令中描述的Java选项之一。例如,-J-Xms48m设置启动内存为48mb。

–limit-modules 限制可观察模块的范围。

–module module-name 或-m module-name 只编译指定的模块并检查时间戳。

–module-path path or -p path 指定查找应用模块的路径。

–module-source-path module-source-path 指定在何处查找多个模块的输入源文件。

–module-version version编译模块的版本号。

-nowarn 禁用警告消息。该选项的操作与-Xlint:none选项相同。

-parameters 为方法参数的反射生成元数据。在生成的类文件中存储构造函数和方法的形参数名,以便Reflection API中的java.lang.reflect.Executable.getParameters方法可以检索它们。

-proc:[none, only]控制是否完成注释处理和编译。-proc:none表示编译不进行注释处理。-proc:only表示只进行注释处理,不进行任何后续编译。
-processor class1[,class2,class3…] 要运行的注释处理器的名称。这将绕过默认的发现过程。

–processor-module-path path 用于查找注释处理器的模块路径。

–processor-path path或-processorpath path 标注处理器的路径。如果不使用此选项,则搜索类路径以查找处理器。

-profile profile 检查所使用的API是否在指定的配置文件中可用。

–release release 针对特定VM版本的公开、支持和文档化的API进行编译。

指定用于放置生成的源文件的目录。如果类是包的一部分,那么编译器将源文件放在反映包名的子目录中,并根据需要创建目录。例如:

  • Linux和macOS:如果你指定-s /home/mysrc,类名为com.mypackage.MyClass,然后源文件放在/home/mysrc/com/mypackage/MyClass.java中。
  • Windows:如果你指定-s C:\mysrc并且这个类名为com.mypackage。然后源文件放在C: mysrc\com\mypackage\MyClass.java中。

-source release 接受的源代码版本。允许的release 如下:

-source 15 编译器接受Java SE 15中引入的特性的代码。

-source 16 默认值。编译器接受带有Java SE 16中引入的特性的代码。

–source-path path或-sourcepath path 指定查找输入源文件的路径。这是用于搜索类或接口定义的源代码路径。与用户类路径一样,源路径条目在Linux和macOS上用冒号(:)分隔,在Windows上用分号(;)分隔。它们可以是目录、JAR归档或ZIP归档。如果使用包,则目录或归档中的本地路径名必须反映包名。

–system jdk | none 覆盖系统模块的位置。

-target release 为指定的VM版本生成类文件。

–upgrade-module-path path 覆盖可升级模块的位置。

-verbose 输出关于编译器正在做什么的消息。消息包括关于加载的每个类和编译的每个源文件的信息。

–version或-version 打印版本信息。

-Werror 在出现警告时终止编译。

javac的交叉编译选项

默认情况下,对于JDK 9之前的版本,类是根据javac命令附带的平台的引导类编译的。但是javac也支持交叉编译,在交叉编译中,类根据不同Java平台实现的引导类进行编译。交叉编译时使用-bootclasspath和-extdirs选项很重要。

额外的选项

–add-exports module/package=other-module(,other-module)当other-module的值为all - named时,指定将被视为从其定义模块导出到其他模块或所有未命名模块的包。
–add-reads module=other-module(,other-module)
指定模块需要考虑的附加模块。

–default-module-for-created-files module-name 指定由注释处理器创建的文件的回退目标模块(如果没有指定或推断出)。

-Djava.endorsed.dirs=dirs 覆盖认可的标准路径的位置。

-Djava.ext.dirs=dirs 覆盖已安装扩展的位置。

–doclint-format [html4|html5] 文档注释的格式。

–patch-module module=file(:file)* 使用JAR文件或目录中的类和资源覆盖或扩充模块。

-Xbootclasspath:path 覆盖引导类文件的位置。

-Xbootclasspath/a:path 为引导类路径添加后缀。

-Xbootclasspath/p:path 为引导类路径添加前缀。

-Xdiags:[compact, verbose] 选择诊断模式。

-Xdoclint 启用javadoc注释中问题的推荐检查。

-xdoclint:(all|none|[-]group)[/access] 启用或禁用指定的检查组。
Group可以有以下值之一:

accessibility
html
missing
reference
syntax

access指定- xdocclint 选项检查的类和成员的最低可见性级别。它可以有以下值之一(按最可见到的顺序):

public
protected
package
private

默认访问级别为private。

有关这些检查组的更多信息,请参阅javadoc命令的-Xdoclint选项。在javac命令中默认禁用-Xdoclint选项。

例如,以下选项检查访问级别为protected或更高(包括protected和public)的类和成员(使用所有检查组):

-Xdoclint:all/protected

-Xdoclint:all,-html/package

-Xdoclint/package:[-]packages(,[-]package)* 启用或禁用特定包中的检查。每个包要么是包的限定名,要么是包名前缀,后跟句点和星号(.*),扩展到给定包的所有子包。每个包可以用连字符(-)作为前缀,以禁用对一个或多个指定包的检查。

-Xlint 启用所有建议的警告。在这个版本中,建议启用所有可用的警告。

-Xlint:[-]key(,[-]key)* 提供启用或禁用的警告,用逗号(,)分隔。在键前面加连字符(-)以禁用指定的警告。

key支持的值有:

        all: Enables all warnings.
        auxiliaryclass: Warns about an auxiliary class that’s hidden in a source file, and is used from other files.
        cast: Warns about the use of unnecessary casts.
        classfile: Warns about the issues related to classfile contents.
        deprecation: Warns about the use of deprecated items.
        dep-ann: Warns about the items marked as deprecated in javadoc but without the @Deprecated annotation.
        divzero: Warns about the division by the constant integer 0.
        empty: Warns about an empty statement after if.
        exports: Warns about the issues regarding module exports.
        fallthrough: Warns about the falling through from one case of a switch statement to the next.
        finally: Warns about finally clauses that do not terminate normally.
        module: Warns about the module system-related issues.
        opens: Warns about the issues related to module opens.
        options: Warns about the issues relating to use of command line options.
        overloads: Warns about the issues related to method overloads.
        overrides: Warns about the issues related to method overrides.
        path: Warns about the invalid path elements on the command line.
        processing: Warns about the issues related to annotation processing.
        rawtypes: Warns about the use of raw types.
        removal: Warns about the use of an API that has been marked for removal.
        requires-automatic: Warns developers about the use of automatic modules in requires clauses.
        requires-transitive-automatic: Warns about automatic modules in requires transitive.
        serial: Warns about the serializable classes that do not provide a serial version ID. Also warns about access to non-public members from a serializable element.
        static: Warns about accessing a static member using an instance.
        try: Warns about the issues relating to the use of try blocks (that is, try-with-resources).
        unchecked: Warns about the unchecked operations.
        varargs: Warns about the potentially unsafe vararg methods.
        none: Disables all warnings.

-Xmaxerrs number 设置打印错误的最大数量。

-Xmaxwarns number 设置打印警告的最大数量。

-Xpkginfo:[always, legacy, nonempty] 指定javac命令何时以及如何使用下列选项之一从package-info.java文件生成package-info.class文件:

    always - Generates a package-info.class file for every package-info.java file. This option may be useful if you use a build system such as Ant, which checks that each .java file has a corresponding .class file.
    legacy - Generates a package-info.class file only if package-info.java contains annotations. This option doesn't generate a package-info.class file if package-info.java contains only comments.
    nonempty - Generates a package-info.class file only if package-info.java contains annotations with RetentionPolicy.CLASS or RetentionPolicy.RUNTIME.

-Xplugin:name args 要运行的插件的名称和可选参数。

-Xprefer:[source, newer] 指定在隐式编译的类中同时找到源文件和类文件时读取哪个文件:

' - xprefer:newer ' -读取某个类型的较新的源文件或类文件(默认)' - xprefer:source ' -读取源文件。当您希望确保任何注释处理器都能访问使用source保留策略声明的注释时,请使用' -Xprefer:source '

-Xprint 打印指定类型的文本表示,用于调试。它不执行注释处理或编译。输出的格式可能会改变。

-XprintProcessorInfo 打印请求处理器处理哪些注释的信息。

  • xprintrount 打印初始和后续注释处理轮的信息。

-Xstdout filename 将编译器消息发送到指定文件。默认情况下,编译器消息转到System.err。

命令行参数文件

参数文件可以以任何组合包括javac选项和源文件名。文件中的参数可以用空格或换行符分隔。如果文件名包含嵌入的空格,则将整个文件名放在双引号中。

参数文件中的文件名相对于当前目录,而不是参数文件的位置。通配符在这些列表中是不允许的(例如用于指定.java)。不支持使用@符号@来递归解释文件。不支持-J选项,因为它们被传递到启动程序,而启动程序不支持参数文件。

在执行javac命令时,以@符号@为前导字符传入每个参数文件的路径和名称。当javac命令遇到以@符号开始的参数时,它将该文件的内容展开到参数列表中。

例子

使用javac @filename的例子

你可以使用一个名为argfile的参数文件来保存所有javac参数:

javac @argfile

这个参数文件可以包含以下两个参数文件示例中所示的两个文件的内容。

您可以创建两个参数文件:一个用于javac选项,另一个用于源文件名。注意,下面的列表没有行延续字符。创建一个名为options的文件,包含以下内容:

Linux and macOS:
-d classes
-g
-sourcepath /java/pubs/ws/1.3/src/share/classes

Windows
-d classes
-g
-sourcepath C:\java\pubs\ws\1.3\src\share\classes

创建一个名为classes的文件,其中包含以下内容:

MyClass1.java
MyClass2.java
MyClass3.java

然后执行如下命令javac:

javac @options @classes

带路径的参数文件

参数文件可以有路径,但文件中的任何文件名都是相对于当前工作目录的(不是path1或path2):

javac @path1/options @path2/classes

使用-Xlint键的示例

不必要的警告和冗余的强制转换,例如:

String s = (String) "Hello!"

classfile 警告与类文件内容相关的问题。

deprecation 对已弃用项目的使用发出警告。例如:

java.util.Date myDate = new java.util.Date();
int currentDay = myDate.getDay();

方法java.util.Date.getDay从JDK 1.1开始就已弃用。

对文档中有@deprecated Javadoc注释但没有@Deprecated 注释的项目发出警告,例如:

/**
  * @deprecated As of Java SE 7, replaced by {@link #newMethod()}
  */
public static void deprecatedMethod() { }
public static void newMethod() { }

divzero 警告常量整数0的除法,例如:

int divideByZero = 42 / 0;

对if语句后的空语句发出警告,例如:

class E {
    void m() {
         if (true) ;
    }
}

fallthrough 检查switch 块中的fall-through情况,并为发现的任何情况提供警告消息。失败案例是指switch块中除最后一个案例外的其他案例,该案例的代码不包含break语句,允许代码执行从该案例失败到下一个案例。例如,这个switch块中case 1标签后面的代码没有以break语句结束:

switch (x) {
case 1:
  System.out.println("1");
  // No break statement here.
case 2:
  System.out.println("2");
}

如果在编译这段代码时使用了-Xlint:fallthrough选项,那么编译器会发出一个警告,警告可能会fall-through into case,并给出问题case的行号。

finally 警告不能正常完成的finally子句,例如:

public static int m() {
  try {
     throw new NullPointerException();
  }  catch (NullPointerException(); {
     System.err.println("Caught NullPointerException.");
     return 1;
   } finally {
     return 0;
   }
  }

在本例中,编译器会为finally块生成一个警告。当调用int方法时,它返回一个值0。当try块退出时,将执行finally块。在本例中,当控制权转移到catch块时,int方法就会退出。但是,finally块必须执行,因此它会执行,即使控制被转移到方法之外。

options 警告与命令行选项使用相关的问题。参见javac的交叉编译选项。

overrides 对与方法重写相关的问题发出警告。例如,考虑以下两个类:

public class ClassWithVarargsMethod {
  void varargsMethod(String... s) { }
}

public class ClassWithOverridingMethod extends ClassWithVarargsMethod {
   @Override
   void varargsMethod(String[] s) { }
}

编译器会生成类似如下的警告:

warning: [override] varargsMethod(String[]) in ClassWithOverridingMethod 
overrides varargsMethod(String...) in ClassWithVarargsMethod; overriding
method is missing '...'

当编译器遇到varargs方法时,它将varargs形参转换为数组。在ClassWithVarargsMethod.varargsMethod方法中,编译器将varargs形参String…s转换为形参数String[] s,一个与ClassWithOverridingMethod.varargsMethod方法的形式参数匹配的数组。因此,这个例子可以编译。

path 警告无效的路径元素和命令行上不存在的路径目录(关于类路径、源路径和其他路径)。这样的警告不能用@SuppressWarnings注释加以抑制。例如:

  • Linux和macOS: javac -Xlint:path -classpath /nonexistentpath Example.java
  • Windows: javac -Xlint:path -classpath C:\nonexistentpath Example.java

processing 警告与注解处理相关的问题。当您有一个具有注解的类,并且您使用的注解处理程序不能处理这种类型的异常时,编译器会生成此警告。例如,下面是一个简单的注解处理器:

import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javaz.lang.model.element.*;

@SupportedAnnotationTypes("NotAnno")
public class AnnoProc extends AbstractProcessor {
  public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv){
     return true;
  }

  public SourceVersion getSupportedSourceVersion() {
     return SourceVersion.latest();
   }
}

@interface Anno { }

@Anno
class AnnosWithoutProcessors { }

下面的命令编译注解处理器AnnoProc,然后在源文件AnnosWithoutProcessors.java上运行这个注解处理器:

javac AnnoProc.java
javac -cp . -Xlint:processing -processor AnnoProc -proc:only AnnosWithoutProcessors.java

当编译器对源文件AnnosWithoutProcessors.java运行注解处理器时,它会生成以下警告:

warning: [processing] No processor claimed any of these annotations: Anno
###没有处理器声明这些注解


要解决这个问题,可以将在AnnosWithoutProcessors类中定义和使用的注解从Anno重命名为NotAnno。

rawtypes 警告未检查的原始类型操作。下面的语句会生成一个rawtypes警告:

void countElements(List l) { ... }

下面的例子不会生成一个rawtypes警告:

void countElements(List<?> l) { ... }

List是一个原始类型。然而, List<?>是一个无界通配符参数化类型。因为List是一个参数化接口,所以总是指定它的类型参数。在这个例子中,List形式参数是用一个无界通配符?作为其形式类型参数,这意味着countElements方法可以接受List接口的任何实例化。

serial 警告在可序列化类上缺少serialVersionUID定义。例如:

public class PersistentTime implements Serializable
{
  private Date time;
 
   public PersistentTime() {
     time = Calendar.getInstance().getTime();
   }
 
   public Date getTime() {
     return time;
   }
}

编译器会生成以下警告:

warning: [serial] serializable class PersistentTime has no definition of
serialVersionUID

如果一个可序列化的类没有显式声明一个名为serialVersionUID的字段,那么序列化运行时环境将根据类的各个方面为该类计算一个默认的serialVersionUID值,如Java对象序列化规范中所述。但是,强烈建议所有可序列化的类都显式声明serialVersionUID值,因为计算serialVersionUID值的默认过程对类的细节非常敏感,这些细节可能会根据编译器实现而变化。因此,这可能会在反序列化期间导致意外的InvalidClassExceptions 。为了在不同的Java编译器实现中保证一致的serialVersionUID值,可序列化类必须声明显式的serialVersionUID值。

static 警告与使用静态变量有关的问题,例如:

class XLintStatic {
    static void m1() { }
    void m2() { this.m1(); }
}

编译器会生成以下警告:

warning: [static] static method should be qualified by type name,
XLintStatic, instead of by an expression

要解决这个问题,你可以调用静态方法m1如下:

XLintStatic.m1();

或者,您可以从方法m1的声明中删除static关键字。

try 警告与try块使用有关的问题,包括try-with-resources语句。例如,由于在try块中声明的资源ac没有被使用,会为下面的语句生成一个警告:

try ( AutoCloseable ac = getResource() ) {    // do nothing}

unchecked 提供Java语言规范要求的未经检查的转换警告的更多细节,例如:

List l = new ArrayList<Number>();
List<String> ls = l;       // unchecked warning

在类型擦除过程中,ArrayList和List类型分别变成ArrayList和List。

ls命令的参数化类型是List。当l引用的List被赋值给ls时,编译器生成一个未选中的警告。在编译时,编译器和JVM不能确定l是否指向List类型。在本例中,l没有引用List类型。因此,会发生堆污染。

当List对象l(其静态类型为List)被分配给另一个List对象ls(其静态类型为List)时,会发生堆污染情况。然而,编译器仍然允许这种赋值。它必须允许这种赋值,以保持与不支持泛型的Java SE版本的向后兼容性。由于类型擦除,List和List都变成List。因此,编译器允许将对象l(其原始类型为List)赋值给对象ls。

varargs 警告不安全使用变量参数(varargs)方法,特别是那些包含非实参的方法,例如:

public class ArrayBuilder {
  public static <T> void addToList (List<T> listArg, T... elements) {
    for (T x : elements) {
      listArg.add(x);
    }
  }
}

非具体化类型是指其类型信息在运行时不能完全可用的类型。对于ArrayBuilder.addToList方法的定义,编译器会生成以下警告:

warning: [varargs] Possible heap pollution from parameterized vararg type T
###警告:[varargs]可能来自参数化的vararg类型T的堆污染

当编译器遇到varargs方法时,它将varargs形参转换为数组。但是,Java编程语言不允许创建参数化类型的数组。在方法ArrayBuilder.addToList中,编译器将varargs形参T…元素转化为形参T[] 元素,一个数组。然而,由于类型擦除,编译器将varargs形参转换为Object[]元素。因此,存在堆污染的可能性。

通过提供命令行参数进行编译的示例

要像提供命令行参数一样编译,请使用以下语法:

JavaCompiler javac = ToolProvider.getSystemJavaCompiler();

该示例将诊断信息写入标准输出流,并返回从命令行调用javac命令时给出的退出码。您可以使用javax.tools.JavaCompiler接口中的其他方法来处理诊断、控制文件的读取和写入位置等等。

编译多个源文件的示例

这个例子编译了问候包中的Aloha.java、GutenTag.java、Hello.java和Hi.java源文件。

Linux和macOS:

% javac greetings/*.java
% ls greetings
Aloha.class         GutenTag.class      Hello.class         Hi.class
Aloha.java          GutenTag.java       Hello.java          Hi.java

Windows:

C:\>javac greetings\*.java
C:\>dir greetings
Aloha.class         GutenTag.class      Hello.class         Hi.class
Aloha.java          GutenTag.java       Hello.java          Hi.java

指定用户类路径示例

在前一个例子中更改一个源文件后,重新编译它:

Linux和macOS:

pwd
/examples
javac greetings/Hi.java

Windows:

C:\>cd
\examples
C:\>javac greetings\Hi.java

因为greetings.Hi引用了greeting包中的其他类,编译器需要找到这些其他类。前面的示例之所以有效,是因为默认的用户类路径是包含包目录的目录。如果您想重新编译这个文件而不关心您所在的目录,那么可以通过设置CLASSPATH将示例目录添加到用户类路径中。本例使用-classpath选项。

Linux and macOS:

javac -classpath /examples /examples/greetings/Hi.java

Windows:

C:\>javac -classpath \examples \examples\greetings\Hi.java
If you change greetings.Hi to use a banner utility, then that utility also needs to be accessible through the user class path.
### 如果你改变greetings.Hi,使用banner 实用程序,那么该实用程序也需要通过用户类路径访问。

Linux and macOS:

javac -classpath /examples:/lib/Banners.jar /examples/greetings/Hi.java

Windows:

C:\>javac -classpath \examples;\lib\Banners.jar \examples\greetings\Hi.java

要执行greetings 包中的类,程序需要访问greetings 包和greetings 类使用的类。

Linux and macOS:

java -classpath /examples:/lib/Banners.jar greetings.Hi

Windows:

C:\>java -classpath \examples;\lib\Banners.jar greetings.Hi

注解处理

javac命令提供了对注释处理的直接支持,取代了对单独的注解处理命令apt的需要。注解处理程序的API在javax.annotation.processing和javax.lang.model包和子包中定义。

注解处理如何工作

除非使用-proc:none选项禁用注解处理,否则编译器将搜索任何可用的注解处理程序。搜索路径可以使用-processorpath选项指定。如果没有指定路径,则使用用户类路径。在搜索路径上通过名为META-INF/services/javax.annotation.processing.Processor 的服务提供者配置文件定位处理器。这样的文件应该包含要使用的任何注解处理程序的名称,每行列出一个。或者,可以使用-processor选项显式指定处理器。在命令行上扫描源文件和类以确定存在哪些注解之后,编译器查询处理程序以确定它们处理哪些注解。当找到匹配项时,将调用处理器。处理器可以声明它处理的注解,在这种情况下,不需要为这些注解寻找任何处理器。声明所有注解之后,编译器不会搜索其他处理器。

如果任何处理器生成新的源文件,那么就会发生另一轮注解处理:扫描所有新生成的源文件,并像以前一样处理注解。在前几轮中调用的任何处理器在随后的所有轮中也会被调用。直到没有生成新的源文件为止。在没有生成新源文件的一轮之后,将最后一次调用注解处理器,给它们一个机会来完成任何剩余的工作。最后,除非使用-proc:only选项,否则编译器将编译原始文件和所有生成的源文件。

搜索类型

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

例如,当您创建java.awt的子类时。您还使用了Window的祖先类:java.awt。容器,java.awt。组件和java . lang . object。当编译器需要类型信息时,它搜索定义类型的源文件或类文件。编译器首先在引导和扩展类中搜索类文件,然后在用户类路径(默认情况下是当前目录)中搜索。用户类路径是通过设置CLASSPATH环境变量或使用-classpath选项定义的。

如果您设置了-sourcepath选项,那么编译器将在指定的路径中搜索源文件。否则,编译器将在用户类路径中搜索类文件和源文件。您可以使用-bootclasspath和-extdirs选项指定不同的引导或扩展类。

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

如果类型搜索本身或通过-Xprefer选项的设置找到所需类型的源文件,那么编译器将读取源文件以获得所需的信息。默认情况下,编译器也编译源文件。您可以使用-implicit选项来指定行为。如果没有指定,则不会为源文件生成类文件。如果指定了class,则为源文件生成类文件。

在注解处理完成之前,编译器可能不会发现需要某些类型信息。当在源文件中找到类型信息且没有指定-implicit 选项时,编译器会发出警告,说明该文件正在编译,而没有进行注解处理。要禁用警告,可以在命令行上指定文件(以便它接受注解处理),或者使用-implicit选项指定是否应该为此类源文件生成类文件。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值