用法: 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