javac命令參數詳解

用法: javac <options> <source files>

其中, 可能的選項包括:

  -g                         在生成的class文件中包含所有調試信息(行號、變量、源文件)

  -g:none                    在生成的class文件中不生成任何調試信息

  -g:{lines,vars,source}     只生成某些調試信息,eclipse的斷點調試功能,就是通過設置此參數實現的。

  -nowarn                    不生成任何警告

  -verbose                   輸出有關編譯器正在執行的操作的消息,包括:classpath、加載的類文件信息

  -deprecation               輸出使用已過時的 API 的源位置,如果你在源文件中使用了“已過時的API”,則生成詳細警告信息

  -classpath <路徑>            指定查找用戶類文件和註釋處理程序的位置

  -cp <路徑>                   指定查找用戶類文件和註釋處理程序的位置

  -sourcepath <路徑>           指定查找輸入源文件的位置

  -bootclasspath <路徑>        覆蓋引導類文件的位置

  -extdirs <目錄>              覆蓋所安裝擴展的位置

  -endorseddirs <目錄>         覆蓋簽名的標準路徑的位置

  -proc:{none,only}          控制是否執行註釋處理和/或編譯。

  -processor <class1>[,<class2>,<class3>...] 要運行的註釋處理程序的名稱; 繞過默認的搜索進程

  -processorpath <路徑>        指定查找註釋處理程序的位置

  -d <目錄>                    指定放置生成的類文件的位置

  -s <目錄>                    指定放置生成的源文件的位置

  -implicit:{none,class}     指定是否爲隱式引用文件生成類文件

  -encoding <編碼>             指定源文件使用的字符編碼,如果源文件使用的UTF-8編碼,而此參數被設定爲GBK,則編譯將出現亂碼

  -source <發行版>              使用指定版本的JDK編譯,比如:-source 1.4表示用JDK1.4的標準編譯,如果在源文件中使用了泛型,則用JDK1.4是不能編譯通過的。

  -target               指定生成的class文件要運行在哪個JVM版本,以後實際運行的JVM版本必須要高於這個指定的版本。

  -version                   版本信息

  -help                      輸出標準選項的提要

  -A關鍵字[=值]                  傳遞給註釋處理程序的選項

  -X                         輸出非標準選項的提要

  -J<標記>                     直接將 <標記> 傳遞給運行時系統

  -Werror                    出現警告時終止編譯

  @<文件名>                     從文件讀取選項和文件名

-g、-g:none、-g:{lines,vars,source}

  • -g:在生成的class文件中包含所有調試信息(行號、變量、源文件)
  • -g:none :在生成的class文件中不包含任何調試信息。

這個參數在javac編譯中是看不到什麼作用的,因爲調試信息都在class文件中,而我們看不懂這個class文件。

爲了看出這個參數的作用,我們在eclipse中進行實驗。在eclipse中,我們經常做的事就是“debug”,而在debug的時候,我們會

  • 加入“斷點”,這個是靠-g:lines起作用,如果不記錄行號,則不能加斷點。
  • 在“variables”窗口中查看當前的變量,如下圖所示,這是靠-g:vars起作用,否則不能查看變量信息。
  • 在多個文件之間來回調用,比如 A.java的main()方法中調用了B.java的fun()函數,而我想看看程序進入fun()後的狀態,這是靠-g:source,如果沒有這個參數,則不能查看B.java的源代碼。

在eclipse中,假設有一個名爲 Test 的項目,則可以"右擊Test項目" -> "Properties" -> "Java compiler",進入下圖界面。

上面用紅色方框圈起來的選項,作用就等價於 -g:vars,-g:lines,-g:source。

下面來做幾個試驗:

實驗一:

  • 實驗內容:去掉全部的三個選項。
  • 結論:不能進行調試,因爲不能加斷點,不能查看當前的變量。

實驗二:

  • 實驗內容:只去掉第1個選項。
  • 結論:在“variables”窗口中,沒有記錄任何變量。

實驗三:

  • 實驗內容:去掉第2個選項。
  • 結論:不能加BreakPoint。

實驗四:

  • 實驗內容:去掉第3個選項。
  • 結論:如果要查看其它文件,則出現: source not found.

-bootclasspath、-extdirs

-bootclasspath和-extdirs 幾乎不需要用的,因爲他是用來改變 “引導類”和“擴展類”。

  • 引導類(組成Java平臺的類):Java\jdk1.7.0_25\jre\lib\rt.jar等,用-bootclasspath設置。
  • 擴展類:Java\jdk1.7.0_25\jre\lib\ext目錄中的文件,用-extdirs設置。
  • 用戶自定義類:用-classpath設置。

我們用-verbose編譯後出現的“類文件的搜索路徑”,就是由上面三個路徑組成,如下:

[類文件的搜索路徑: C:\Java\jdk1.7.0_25\jre\lib\resources.jar,C:\Java\jdk1.7.0_25
\jre\lib\rt.jar,C:\Java\jdk1.7.0_25\jre\lib\sunrsasign.jar,C:\Java\jdk1.7.0_25\j
re\lib\jsse.jar,C:\Java\jdk1.7.0_25\jre\lib\jce.jar,C:\Java\jdk1.7.0_25\jre\lib\
charsets.jar,C:\Java\jdk1.7.0_25\jre\lib\jfr.jar,C:\Java\jdk1.7.0_25\jre\classes
,C:\Java\jdk1.7.0_25\jre\lib\ext\access-bridge-32.jar,C:\Java\jdk1.7.0_25\jre\li
b\ext\dnsns.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\jaccess.jar,C:\Java\jdk1.7.0_25\
jre\lib\ext\localedata.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunec.jar,C:\Java\jdk
1.7.0_25\jre\lib\ext\sunjce_provider.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunmsca
pi.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunpkcs11.jar,C:\Java\jdk1.7.0_25\jre\lib
\ext\zipfs.jar,..\bin]             //紫色表示引導類和擴展類路徑,綠色表示用戶定義類路徑

如果利用 -bootclasspath 重新定義: javac -bootclasspath src Xxx.java,則會出現下面錯誤:

致命錯誤: 在類路徑或引導類路徑中找不到程序包 java.lang

-sourcepath和-classpath(-cp)

  • -classpath(-cp)指定你依賴的類的class文件的查找位置。在Linux中,用“:”分隔classpath,而在windows中,用“;”分隔。
  • -sourcepath指定你依賴的類的java文件的查找位置。

舉個例子,

複製代碼

public class A
{
    public static void main(String[] args) {
        B b = new B();
        b.print();
    }
}

複製代碼

複製代碼

public class B
{
    public void print()
    {
        System.out.println("old");
    }
}

複製代碼

目錄結構如下:

sourcepath          //此處爲當前目錄
  |-src
    |-com
      |- B.java
    |- A.java
  |-bin
    |- B.class               //是 B.java 編譯後的類文件

如果要編譯 A.java,則必須要讓編譯器找到類B的位置,你可以指定B.class的位置,也可以是B.java的位置,也可以同時都存在。

javac -classpath bin src/A.java                            //查找到B.class
javac -sourcepath src/com src/A.java                   //查找到B.java
javac -sourcepath src/com -classpath bin src/A.java    //同時查找到B.class和B.java

如果同時找到了B.class和B.java,則:

  • 如果B.class和B.java內容一致,則遵循B.class。
  • 如果B.class和B.java內容不一致,則遵循B.java,並編譯B.java。

以上規則可以通過 -verbose選項看出。

-proc:{none,only}、-procpath、-processor

這三個命令是用來自定義“Annotation Processor”的,即你可以自定義註釋,比如@Hello,@First 等,解析這些註釋就需要"Annotation Processor"。

  • -processor <CustomProcessor> :自定義註釋處理器的類
  • -procpath:註釋處理器的查找目錄。
  • -proc:only:只運行註釋處理器,而不編譯源文件。
  • -proc:none:不使用註釋處理器,只編譯源文件。

任務:自定義一個@HelloWorld 註釋,並自定義註釋處理器“HelloWorldProcessor”,使得在javac編譯時輸出:HelloWorld.

第一步:定義 @HelloWorld註釋。

public @interface HelloWorld
{    
}

第二步:使用@HelloWorld註釋。

@HelloWorld
public class Dummy
{
}

第三步:編寫註釋處理器 HelloWorldProcessor。

  • 必須要繼承 AbstractProcessor.
  • 對於process方法,每個Annotation都會調用process()方法一次。

複製代碼

 1 import java.util.Set;
 2 import javax.annotation.processing.*;
 3 import javax.lang.model.SourceVersion;
 4 import javax.lang.model.element.TypeElement;
 5 import javax.tools.Diagnostic;
 6 
 7 @SupportedAnnotationTypes("HelloWorld")            //註釋處理器支持的註釋:HelloWorld
 8 @SupportedSourceVersion(SourceVersion.RELEASE_7)        //註釋處理器支持的JDK版本:7
 9 public class HelloWorldProcessor extends AbstractProcessor {        //繼承 AbstractProcessor
10      @Override
11      public synchronized void init(ProcessingEnvironment processingEnv) 
12      {
13          super.init(processingEnv);
14      }
15 
16      @Override
17      public boolean process(Set<? extends TypeElement> annotations,
18                                 RoundEnvironment roundEnv) 
19      {
20          if (!roundEnv.processingOver()) {
21              processingEnv.getMessager().printMessage(    //註釋處理器的報告
22              Diagnostic.Kind.NOTE, "Hello World!");
23          }
24          return true;
25      }
26 }

複製代碼

在命令行中輸入:

javac HelloWorldProcessor.java 
javac -processor HelloWorldProcessor *.java        

輸出:

注: Hello World!

-d

  • d就是 destination,用於指定.class文件的生成目錄,在eclipse中,源文件都在src中,編譯的class文件都是在bin目錄中。

這裏我用來實現一下這個功能,假設項目名稱爲project,此目錄爲當前目錄,且在src/com目錄中有一個Main.java文件。‘

複製代碼

package com;
public class Main
{
    public static void main(String[] args) {
        System.out.println("Hello");
    }
}

複製代碼

javac -d bin src/com/Main.java

上面的語句將Main.class生成在bin/com目錄下。

-implicit:{none,class}

  • 如果有文件爲A.java(其中有類A),且在類A中使用了類B,類B在B.java中,則編譯A.java時,默認會自動編譯B.java,且生成B.class。
  • implicit:none:不自動生成隱式引用的類文件。
  • implicit:class(默認):自動生成隱式引用的類文件。
public class A
{
    public static void main(String[] args) {
        B b = new B();
    }
}
public class B
{
}

如果使用:

 javac -implicit:none A.java

則不會生成 B.class。

-source和-target

  • -source:使用指定版本的JDK編譯,比如:-source 1.4表示用JDK1.4的標準編譯,如果在源文件中使用了泛型,則用JDK1.4是不能編譯通過的。
  • -target:指定生成的class文件要運行在哪個JVM版本,以後實際運行的JVM版本必須要高於這個指定的版本。

javac -source 1.4 Xxx.java

javac -target 1.4 Xxx.java

-encoding

  • 指定源文件的編碼格式,如果源文件是UTF-8編碼的,而-encoding GBK,則源文件就變成了亂碼(特別是有中文時)。

javac -encoding UTF-8 Xxx.java

-deprecation

  • 如果你在源文件中使用了“已過時的API”,則生成詳細警告信息。
1 import java.util.Date;
2 public class Javac01
3 {
4     public static void main(String[] args) {
5         Date date = new Date(2012,12,12);6     }
7 }

上面的代碼中,第5行使用了過時的API,如果使用 javac Javac01.java 編譯,則生成:

注: Javac01.java使用或覆蓋了已過時的 API。
注: 有關詳細信息, 請使用 -Xlint:deprecation 重新編譯。

上面的輸出並不詳細。但是如果使用 javac -deprecation Javac01.java 編譯,則:

Javac01.java:5: 警告: [deprecation] Date中的Date(int,int,int)已過時
Date date = new Date(2012,12,12);
                     ^

-verbose

輸出詳細的編譯信息,包括:classpath、加載的類文件信息。

比如,我寫了一個最簡單的HelloWorld程序,在命令行中輸入:

D:\Java>javac -verbose -encoding UTF-8 HelloWorld01.java

輸出:

[語法分析開始時間 RegularFileObject[HelloWorld01.java]]
[語法分析已完成, 用時 21 毫秒]
[源文件的搜索路徑: .,D:\大三下\編譯原理\cup\java-cup-11a.jar,E:\java\jflex\lib\J           //-sourcepath
Flex.jar]
[類文件的搜索路徑: C:\Java\jdk1.7.0_25\jre\lib\resources.jar,C:\Java\jdk1.7.0_25      //-classpath、-bootclasspath、-extdirs
\jre\lib\rt.jar,C:\Java\jdk1.7.0_25\jre\lib\sunrsasign.jar,C:\Java\jdk1.7.0_25\j
re\lib\jsse.jar,C:\Java\jdk1.7.0_25\jre\lib\jce.jar,C:\Java\jdk1.7.0_25\jre\lib\
charsets.jar,C:\Java\jdk1.7.0_25\jre\lib\jfr.jar,C:\Java\jdk1.7.0_25\jre\classes
,C:\Java\jdk1.7.0_25\jre\lib\ext\access-bridge-32.jar,C:\Java\jdk1.7.0_25\jre\li
b\ext\dnsns.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\jaccess.jar,C:\Java\jdk1.7.0_25\
jre\lib\ext\localedata.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunec.jar,C:\Java\jdk
1.7.0_25\jre\lib\ext\sunjce_provider.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunmsca
pi.jar,C:\Java\jdk1.7.0_25\jre\lib\ext\sunpkcs11.jar,C:\Java\jdk1.7.0_25\jre\lib
\ext\zipfs.jar,.,D:\大三下\編譯原理\cup\java-cup-11a.jar,E:\java\jflex\lib\JFlex
.jar]
[正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j
ar/java/lang/Object.class)]]
[正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j
ar/java/lang/String.class)]]
[正在檢查Demo]
[正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j
ar/java/lang/AutoCloseable.class)]]
[正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j
ar/java/lang/System.class)]]
[正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j
ar/java/io/PrintStream.class)]]
[正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j
ar/java/io/FilterOutputStream.class)]]
[正在加載ZipFileIndexFileObject[C:\Java\jdk1.7.0_25\lib\ct.sym(META-INF/sym/rt.j
ar/java/io/OutputStream.class)]]
[已寫入RegularFileObject[Demo.class]]
[共 447 毫秒]

編寫一個程序時,比如寫了一句:System.out.println("hello"),實際上還需要加載:Object、PrintStream、String等類文件,而上面就顯示了加載的全部類文件。

-J <標記>

  • 傳遞一些信息給 Java Launcher.

javac -J-Xms48m   Xxx.java          //set the startup memory to 48M.

-@<文件名>

如果同時需要編譯數量較多的源文件(比如1000個),一個一個編譯是不現實的(當然你可以直接 javac *.java ),比較好的方法是:將你想要編譯的源文件名都寫在一個文件中(比如sourcefiles.txt),其中每行寫一個文件名,如下所示:

HelloWorld01.java
HelloWorld02.java
HelloWorld03.java

則使用下面的命令:

javac @sourcefiles.txt

發佈了58 篇原創文章 · 獲贊 17 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章