跳轉到內容

編譯

75% developed
來自華夏公益教科書,開放的書籍,開放的世界

導航 入門 主題: v  d  e )


在 Java 中,程式不會編譯成可執行檔案;它們被編譯成位元組碼(如之前所述),然後 JVM(Java 虛擬機器)在執行時執行它。當我們使用 javac 編譯器時,Java 原始碼被編譯成位元組碼。位元組碼以 .class 副檔名儲存到磁碟上。當程式要執行時,位元組碼會使用即時 (JIT) 編譯器進行轉換。結果是機器碼,然後被送入記憶體並執行。

Java 程式碼需要編譯兩次才能執行

  1. Java 程式需要編譯成位元組碼。
  2. 當位元組碼執行時,它需要被轉換成機器碼。

Java 類/位元組碼在第一次需要時被 JVM 編譯成機器碼並載入到記憶體中。這與 C/C++ 等其他語言不同,在這些語言中,程式需要編譯成機器碼並連結以建立可執行檔案,然後才能執行。

快速編譯過程

[編輯 | 編輯原始碼]

要執行您的第一個 Java 程式,請按照以下說明進行操作

1. 如果您已成功安裝並配置好系統以使用 Java,如這裡所述,則繼續執行。
2. 開啟您首選的文字編輯器 - 這是您在安裝 Java 平臺時設定的編輯器。
例如,在 Windows 上使用 記事本Notepad++;在 Linux 上使用 GeditKateSciTE;或者,在 Mac OS 上使用 XCode 等。
3. 在新的文字文件中編寫以下程式碼行
Computer code 程式碼清單 2.5: HelloWorld.java
public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World!");
  }
}
4. 將檔案儲存為 HelloWorld.java - 您的檔名應與您的類定義的名稱相同,並在後面加上 .java 副檔名。此名稱是區分大小寫的,這意味著您需要將類定義名稱中的字母大小寫與您儲存的檔名大小寫保持一致。
5. 接下來,開啟您首選的命令列應用程式。
例如,在 Windows 上使用 命令提示符;在 Linux 和 Mac OS 上使用 終端
6. 在命令列應用程式中,導航到您剛剛建立檔案的目錄。如果您不知道如何執行此操作,請考慮閱讀我們的命令列應用程式速成課程,適用於WindowsLinux
7. 使用以下命令編譯 Java 原始檔,如果您需要,您可以複製貼上。
Computer code 編譯
javac HelloWorld.java
Warning 如果您得到類似於 error: cannot read: HelloWorld.java 1 error 的錯誤訊息,則您的檔案不在當前資料夾中或拼寫錯誤。您是否使用cd (change directory) 命令在命令提示符中導航到程式所在位置?

如果您得到另一個以 1 error... errors 結尾的訊息,則您的程式碼中可能存在錯誤。您是否確定所有單詞的拼寫都正確,並且大小寫與所示完全一致?分號和括號是否在適當的位置?您是否缺少引號?通常,現代 IDE 會嘗試在這種情況下將整個原始碼著色為引號。

如果您的計算機發出蜂鳴聲,則您的 HelloWorld.java 中可能包含非法字元。

如果沒有在同一個資料夾中建立 HelloWorld.class 檔案,則您遇到了錯誤。您是否正確啟動了 javac 程式?

8. 一旦編譯器返回到提示符,請使用以下命令執行應用程式
Computer code 執行
java HelloWorld
Warning 如果您得到類似於 Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld 的錯誤訊息,則 HelloWorld.class 檔案不在當前資料夾中或拼寫錯誤。

如果您得到類似於 Exception in thread "main" java.lang.NoSuchMethodError: main 的錯誤訊息,則您的原始檔可能編寫錯誤。

9. 上面的命令應導致您的命令列應用程式顯示以下結果
Computer code 輸出
Hello World!
如果程式沒有正確執行,請在本章的討論頁面中尋求幫助.

自動編譯依賴類

[編輯 | 編輯原始碼]

在 Java 中,如果您使用了對任何其他 java 物件的引用,那麼該物件的類將被自動編譯,如果它還沒有被編譯的話。這些自動編譯是巢狀的,並且會一直持續到所有執行程式所需的類都被編譯完成。因此,通常只編譯高階類就足夠了,因為所有依賴類都會被自動編譯。

Computer code 主類編譯
javac ... MainClass.java

但是,如果您程式使用反射來建立物件,或者您正在為 servlet 或“jar”包編譯,則不能依賴此功能。在這些情況下,您應該列出這些類以進行顯式編譯。

Computer code 主類編譯
javac ... MainClass.java ServletOne.java ...

包、子目錄和資源

[編輯 | 編輯原始碼]

每個 Java 頂級類都屬於一個包(在關於的章節中介紹)。這可以在檔案開頭的package語句中宣告;如果缺少該語句,則該類屬於未命名包。

為了編譯,檔案必須位於正確的目錄結構中。包含未命名包中類的檔案必須位於當前/根目錄中;如果類屬於某個包,則它必須位於與包同名的目錄中。

慣例是,與包相對應的包名和目錄名僅包含小寫字母。

頂級包

[編輯 | 編輯原始碼]

具有此包宣告的類

Example 程式碼節 2.1:包宣告
package example;

必須位於名為example的目錄中。

具有此包宣告的類

Example 程式碼節 2.2:帶子包的包宣告
package org.wikibooks.en;

必須位於名為en的目錄中,該目錄必須是wikibooks的子目錄,而wikibooks又必須是org的子目錄,最終形成Linux上的org/wikibooks/en或Windows上的org\wikibooks\en

Java 程式通常包含非程式碼檔案,例如影像和屬性檔案。這些通常稱為資源,並存儲在它們所用類的本地目錄中。例如,如果類com.example.ExampleApp使用icon.png檔案,則該檔案可以儲存為/com/example/resources/icon.png。當程式編譯時,這些資源會帶來問題,因為javac不會將它們複製到.class檔案正在編譯到的位置(見上文);程式設計師需要自己移動資原始檔和目錄。

檔名大小寫

[編輯 | 編輯原始碼]

Java 原始檔名必須與檔案包含的公共類名相同。每個檔案只能定義一個公共類。Java 類名和原始檔名都區分大小寫。

類名命名規範是首字母大寫。

編譯器選項

[編輯 | 編輯原始碼]

除錯和符號資訊

[編輯 | 編輯原始碼]
Clipboard

待辦事項
完成本節。


要除錯到 Java 系統類(如 String 和 ArrayList),您需要使用編譯了“除錯資訊”的 JRE 特殊版本。JDK 中包含的 JRE 提供了此資訊,但常規 JRE 則沒有。常規 JRE 不包含此資訊,以確保更好的效能。


   Modern compilers do a pretty good job converting your high-level code, with its nicely indented and nested control structures and arbitrarily typed variables into a big pile of bits called machine code (or bytecode in case of Java), the sole purpose of which is to run as fast as possible on the target CPU (virtual CPU of your JVM). Java code gets converted into several machine code instructions. Variables are shoved all over the place – into the stack, into registers, or completely optimized away. Structures and objects don’t even exist in the resulting code – they’re merely an abstraction that gets translated to hard-coded offsets into memory buffers.
   So how does a debugger know where to stop when you ask it to break at the entry to some function? How does it manage to find what to show you when you ask it for the value of a variable? The answer is – debugging information.
   Debugging information is generated by the compiler together with the machine code. It is a representation of the relationship between the executable program and the original source code. This information is encoded into a pre-defined format and stored alongside the machine code. Many such formats were invented over the years for different platforms and executable files.


符號資訊:符號解析在類載入時在連結解析步驟中完成。它是用直接引用替換型別中的符號引用的過程。它是透過在方法區中搜索以定位所引用實體來完成的。

JIT 編譯器

[編輯 | 編輯原始碼]

即時 (JIT) 編譯器是將位元組碼轉換為機器碼的編譯器。它一次編譯位元組碼,並且編譯後的機器碼會反覆使用,以加快執行速度。早期的 Java 編譯器每次使用位元組碼時都會將其編譯為機器碼,但更現代的編譯器會快取此機器碼以在機器上重複使用。即使如此,Java 的 JIT 編譯仍然比“解釋語言”更快,在解釋語言中,程式碼每次使用時都從高階語言而不是從位元組碼編譯。

標準 JIT 編譯器按需執行。當方法被反覆呼叫時,JIT 編譯器會分析位元組碼並生成高效的機器碼,執行速度非常快。JIT 編譯器足夠智慧,可以識別程式碼是否已編譯,因此,隨著應用程式的執行,編譯只會根據需要發生。隨著 Java 應用程式的執行,它們往往會變得越來越快,因為 JIT 可以對程式碼進行執行時分析和最佳化以滿足執行環境。執行不頻繁的方法或程式碼塊接收的最佳化較少;執行頻繁的方法或程式碼塊(所謂熱點)接收的分析和最佳化更多。


華夏公益教科書