Overview of Content
本文將深入介紹Java應用的各個方面,從原始檔的結構到 Java 程式的進入點 main 函數。
我們將探討JDK管理應用的基本結構,包括 javac 編譯原始文件、java 執行應用以及 jar 打包和解壓。此外,我們還將介紹JavaDoc文件的撰寫與生成,包括JavaDoc標籤的使用和javadoc命令的執行。無論您是初學者還是有經驗的開發者,這篇文章都將為您提供全面且實用的指導,幫助您更好地理解和應用Java應用與編譯的相關知識。
寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀
Java 應用與編譯
Java 應用由多附檔名為 .java
的檔案構成(Java 原始檔),以編譯的角度來看則是待編譯的 編譯單元 (Compilation Unit
)
public class HelloJava {
}
Java 原始檔:結構
● Java 原始檔內可以包含以下內容,這些內容有部份有一些限制
內容關鍵字 | 說明 | 限制 |
---|---|---|
package | 套件宣告敘述,描述該類在 Java 套建中的位置 | 非必須,但如果存在,那 只能有一個、必須 在檔案最頂端(除了註解之外) |
import | 套件引用 | 0 ~ 多個 |
class | 類 | 0 ~ 多個,下面會多做說明 |
interface | 界面 | 0 ~ 多個 |
● JDK 有提供一些基本 Java 套件,我們可以用
package
將其做一些簡單的分類;JDK 的所有套件類也被稱為 J2SE API
JDK 套件名 功能概述 java.lang
包含 Thread
、Exception
、System
、Integer
、String
… 等等類(它是 JVM 自動引用的套件)java.awt
、java.swing
抽象工具箱套件,可用來建立 GUI 畫面 java.io
Input/Output 套件 java.util
工具類別,包含 Date
、Collection
… 等等java.net
支援 TCP/IP 網路協定,包含 Socket、URL 相關的類別 javax.*
對基本套件的擴充 (聲音程式 javax.sound
)
● package
套件說明:
套件 package
非必須,而如果有,那 只能有一個、必須 在檔案最頂端(除了註解之外;其路徑使用 .
取代 /
符號
而 package
描述是相對於 Java 包的路徑 (路徑為 src/main/java
或是 src/main/kotlin
之下)
假設我的原始擋在專案中的路徑為
/src/main/java/hello/FirstJava.java
,那package
則是描述為package hello;
● 而套件的作用如下
A. 透過 package
對路徑的描述,能區分名稱相同的類名
同類名用在同一個檔案中,就必須使用 全路徑呼叫類 編譯器才不會搞錯
B. 受到存取許可全的約束(Java 有檔案區域許可全的約束)
C. 有助於劃分、組織 Java 應用的是的類別,將相關類匯聚且分類
● class
類說明:class
關鍵字用來聲明該檔案中有哪些類,而 Java 檔名、public 類 關係 有兩種狀況,如下
A. 一個 Java 檔中,可以不必有 public 類
class HelloJava {
}
class WorldJava {
}
B. 如果有 public 描述的類,那 Java 原始檔檔名也必須與這個 public 描述的類相同
// 檔名必須為 HelloJava.java
public class HelloJava {
}
class WorldJava {
}
● import
類說明:
import
關鍵字用來引入不同 package
路徑的類,並且 依照寫法會引入不同的類
A. 不同的引入方式
// 只引入 ~/hello/world/FirstImport 類
import hello.world.FirstImport;
// 引入 ~/hello/world/ 包下的所有類
import hello.world.*;
// 引入 ~/hello/ 包下的所有類
import hello.*;
B. 要注意的是 *
號只會引入該目錄下的所有類,並不包括子資料夾的類
// 只引入 ~/hello/world/FirstImport 類
import hello.world.FirstImport;
// 引入 ~/hello/ 包下的所有類,**不包括 world 資料夾內的類!**
import hello.*;
● 對編譯速度的影響?
import` 用來告訴編譯器該檔案存在套件中的哪裡,如果你能 清晰的指出套件位置,那就可以加快編譯器搜尋檔案的速度
● 引入就代表了初始化?
Nonono~ 使用
import
時,不會導致類別的初始化(不會觸發 ClassLoader 加載類)
Java 程式進入點 main
● main
方法是 Java 應用程式的進入點,它必須存在於某個類中(包含程式進入點 main
的類,稱之為主程式類別(mainclass
);main
方法須符合以下四個條件
A. 存取限制 public
B. 靜態方法 static
C. 參數限制 String[] args
D. 返回 void
// 主程式類別為 HelloJava
public class HelloJava {
// 必須四個條件都符合
public static void main(String[] args) {
}
}
● 怎樣對
main
函數傳入參數?首先先使用
javac
編譯源碼,再使用java
命令執行以下格式就可以對 main 函數傳入參數javac <javasource> java [options] <mainclass> [args...]
JDK 管理應用:結構、編譯、打包
管理 Java 應用程式是指 建立 Java 應用程式的目錄結構、編譯、執行、發布 Java 應用程式的操作;下表為 Java 應用常用的開發目錄
目錄 | 說明 |
---|---|
src | 存放 Java 原始檔 |
classes | 編譯過後的 Java 類別檔 (路徑與 src 原始檔批配) |
lib | 其他 .jar 包 |
doc , dec/api | 存放 JavaDoc 相關文件 |
deploy | 存放 Java 應用程式的包裹檔案(Jar 文件) |
JDK 結構簡介
● JDK Java Development Kit
它提供 Java 應用程式基礎的開發、執行環境;其中包括以下重點組件
A. Java 虛擬機:負責 解析、執行 Java 程式,它代替我們與各平台差異的機器溝通(因此 Java 應用不受限於平台限制)
B. JDK 庫:如先前介紹,提供開發者基礎的各個套件使用
C. 開發工具:開發工具都是些可執行程式,如下
JDK 提供的開發工具 | 功能 |
---|---|
javac | 編譯工具 |
java | 執行工具 |
javadoc | 生成 JavaDoc 文件的工具 |
jar | 打包、解開 Java 包的工具 |
javac 編譯原文件
● javac 命令用於編譯 Java 原始檔,命令格式如下
javac [options] [sourcefiles]
常見的 option 如下
javac option | 說明 |
---|---|
-nowarn | 不輸出警告資訊 |
-verbose | 輸出編譯執行中的詳細資訊 |
-deprecation | 輸出程式中 Deprecated API 的具體位置 |
-classpath <路徑> | 覆蓋 classpath 環境變數,用來指定編譯時搜尋相關檔案的路徑(常用在第三方 jar 包),如果沒指定則預設當前目錄 |
-sourcepath <路徑> | 指定 Java 原始檔的路徑 |
-d <目錄> | 編譯後預計輸出 class 到哪個目標目錄 |
●
-classpath
指定的是編譯時尋找可用.class
的目錄;如果你要編譯的檔案他所需要的
.class
檔案在同層目錄,那你應該指定它的上層目錄,而不是上層目錄A. 源碼目錄:
apple.java
依賴banana.java
# 目錄 src test/ |-- apple.java |-- banana.java
B. 分開來編譯:
● 先編譯
apple.java
,下達以下命令會產生apple.class
# 切換到目錄 cd test/ javac apple.java
● 再編譯
banana.java
,下達以下命令會產生banana.class
# 由於你已經在源碼目錄內,所以必須指定其上層目錄! # 因為 javac 會尋找的是目錄,假設你指定當前目錄 . 或是 `pwd` # 那它會找不到 class 檔案 javac -classpath .. banana.java
範例:當前目錄如下
A. CLI 切換到 Main.java
目錄之下並執行以下命令
javac -verbose \
-sourcepath `pwd` \
-classpath ../classes \
-d ../classes \
Main.java
● 編譯器先到
-classpath
指定的目錄下尋找是否有Main.class
檔案,如果沒有再到-sourcepath
指定的目錄下尋找Main.java
檔● 如果同時找到
Main.class
、Main.java
檔案,那就會比較 class 檔案是否過期,如果過期就重新編譯 java 檔● 如果只找到
Main.class
就直接用● 如果只找到
Main.java
就將其編譯程 class 檔● 都找不到就拋出錯誤!
B. javac 就會將 Java 原始檔編譯,並放置 classes
目錄之下
java 執行應用
● java 命令用於執行編譯過後的 class,命令格式如下
java [options] <classfiles>
常見的 option 如下
java option | 說明 |
---|---|
-verbose | 輸出執行中的詳細資訊 |
-classpath <路徑> | 覆蓋 classpath 環境變數,用來指定編譯時搜尋相關檔案的路徑(常用在第三方 jar 包),如果沒指定則預設當前目錄 |
-D<屬性=數性值> | 這個數性值會定應到 System API,System.getProperty("屬性") 中 |
-jar | 執行 Jar 檔案中的特定 Java 類別(必須給予完整路徑) |
範例:
A. 沒有包(Package)的類:
停留在 src/
目錄下,並執行以下命令就可以執行 class 檔
java -classpath ../classes/ Main
如果有多個 classpath 可以使用
;
符號分離不同路徑eg.
java -classpath ../classes/; ../classesA/; ../classes/B; Main
● 尋找
classpath
classpath 會從最近的設定開始尋找,尋找的優先級如:命令設定的
-classpath
> shell 設定的classpath
> 系統設定的classpath
●
package
設定運行時 java 會判斷 class 檔案內的
package
值,並到對應資料夾中找class
檔案,如果找不到則會拋出
B. 有包(Package)的類:
呼叫某個包內 Class 內部的 Main,呼叫的格式 <包名*>.<類名>
package samplePackage;
public class Apple {
public static void main(String[] args) {
System.out.println("Hello Apple");
}
}
編譯、執行指令如下
javac src/samplePackage/Apple.java
# 指定到 src 目錄下找 class
# 找 samplePackage 包下的 Apple
java -classpath ./src samplePackage.Apple
● 而
-classpath
的設定則要依照你要呼叫的類的package
& 你當前的路徑去做設定當前路徑是
/Users/Hy-KylePan/IdeaProjects/JavaTest
Class 檔案是在當前路徑下的
src/samplePackage/Apple.class
而 Apple.class 的
package
是 samplePackage,相較之下是缺少了./src
目錄,所以-classpath
要設定./src
jar 打包、解開
● jar (Java archive
) 命令用於打包 class 檔案(可多個),將其包裹到 JAR 檔,命令格式如下
jar [options] [sourcefiles]
常見的 option 如下
jar option | 說明 |
---|---|
-c | 創建 JAR 檔案 |
-v | 輸出打包、解開時的詳細資訊 |
-f | 指定輸出的目錄 |
-x | 解開 JAR 檔案 |
範例:
A. 停留在 src/
目錄下,並執行以下命令,打包一個 myJar.jar
檔案到 deploy
目錄下
# 尚未編譯請先編譯
javac ../src/com/example/*.java -sourcepath ../src/ -d ../classes/
jar -cvf ./myJar.jar ../classes/com/example/*.class
可使用
*.class
代表該目錄下的所有文件
B. JAR 包也可以透過 jar
命令解開;以下將 myJar.jar
解開,並將內容放置當前目錄(沒有指定)
jar -xvf ./myJar.jar
●
META-INF/MANIFEST.MF
檔案該檔案描述了 JAR 檔的資訊
Manifest-Version: 1.0 Created-By: 17.0.7 (JetBrains s.r.o.)
● 而我們前面有提到
java
命令可以指定-jar
並找到對應的類執行,如果要達成這個條件就要稍微修改一下解開的 jar 包;步驟如下A. 在
classes
目錄下創建Manifest.txt
檔案touch classes/Manifest.txt
B. 將主程式類別寫入
Manifest.txt
檔案Main-Class: com.example.Main
要寫入 全類名!(由於當前範例就是直接在
java
目錄下,所以很單純)● 坑:必須以換行結束!
C. 重新打包
classes
目錄下的檔案,在這邊會 用m
來指定 MANIFESTjar -cvfm ../deploy/specificManifest.jar \ ./classes/Manifest.txt *.*
● 測試使用
java
並指定jar
執行java -jar /home/alien/IdeaProjects/java_learn/deploy/specificManifest.jar
產出 JavaDoc 文件
Java 類可以透過 JavaDoc 文件來對外公佈方法用法;JavaDoc 文件是 基於 HTML 格式 的說明文件,而 JDK 也提供給我們產生說明檔的 javadoc
命令
在原始 Java 檔中,從 /**
註解到 */
結束,內部包含的文件就會輸出到 HTML 中
● 如果註解是在
package
描述前,那就會被javadoc
命令忽略
/**
* <p><strong>This is main class</strong></p>
*/
public class TestMain {
/**
* @param args is input from user or other process.
*/
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
JavaDoc 標籤
● 可在註解中使用特殊符號幫助 JavaDoc 建立標籤,符號如下
JavaDoc 標籤 | 描述 |
---|---|
@version | 指定版本資訊 |
@since | 可說明該方法、類最早出現的版本 |
@author | 指定作者 |
@see | 生成參考其他 JavaDoc 文檔 |
@link | 生成參考其他 JavaDoc 文件的連結(與 @see 差別在,它可嵌入到註解中,並為特定註解中的特定詞彙生成連結) |
@deprecated | 標示該方法、類已經被棄用 |
@param | 描述方法的參數(不可以用來描述類) |
@return | 描述方法的返回值 |
@throws | 描述方法拋出的例外 |
A. @see
範例:
/**
* <p><strong>This is main class</strong></p>
*/
public class TestMain {
/**
* @param args is input from user or other process.
*/
public static void main(String[] args) {
System.out.println("Hello world!");
}
/**
* Default value is 0
*/
private int value = 0;
/**
* @see #value show self param of `value`.
* @see #setValue(int) Use this method to set value.
*/
public void showValue() {
System.out.println("Value: " + value);
}
/**
* Set new value for instance that TestMain.
* @param value new value.
*/
public void setValue(int value) {
this.value = value;
}
}
執行以下命令生成檔案
javadoc -public -protected -private -sourcepath src/ -d ./doc com.example
B. @link
範例:與 @see
差別在,它可嵌入到 HTML 註解中形成連接,範例如下
/**
* <p><strong>This is link class</strong></p>
*/
public class TestLink {
boolean isStart = false;
/**
* <ul>
* <li>if {@link #isStart isStart} is false, show sleeping.</li>
* <li>if {@link #isStart isStart} is true, show working.</li>
* </ul>
*/
public void showState() {
if (isStart) {
System.out.println("Start working.");
} else {
System.out.println("Sleeping.");
}
}
}
執行以下命令生成檔案
javadoc -public -protected -private -sourcepath src/ -d ./doc com.example
javadoc 命令
● javadoc 命令可以用來分析源碼並通過源碼的註解去生產 HTML,指令格式如下
javadoc [options] [packagenames] <sourcefiles>
● 如果
sourcefiles
要使用目錄的話,須使用.
替換/
符號;如果是指定某個檔案就不用替換,繼續保持/
符號
以下幾是 javadoc
常用的 Options
Options | 作用 | 是否預設 |
---|---|---|
-public | 只為 public 級別生成 Javadoc 文件 | N |
-protected | 只為 public、protected 級別生成 Javadoc 文件 | Y |
-package | 只為 public、protected、package 級別生成 Javadoc 文件 | N |
-private | 為所有級別生成 Javadoc 文件 | N |
-version | 解析 @version 標籤 | N |
-author | 解析 @author 標籤 | N |
-splitindex | 將索引分為每個字母對應一個索引檔 | N |
-sourcepath <路徑> | 指定 Java 原始碼路徑 | Y (預設為當前目錄) |
-classpath <路徑> | 指定 classpath | Y (預設為當前目錄) |
-d <目錄> | 指定 Javadoc 文件的輸出目錄 | Y (預設為當前目錄) |
範例:
A. 生成指定指定文件
javadoc -protected \
-sourcepath src/ \
-d ./doc \
src/com/example/TestLink.java
● 如果有特別指定文件,那就 javadoc 不會自動處理別的文件
B. 透過 index 標記生成的檔案(方便尋找)
javadoc -splitindex \
-protected \
-sourcepath src/ \
-d ./doc \
com.example
更多的 Java 語言相關文章
Java 語言深入
● 在這個系列中,我們全方位地探討了 Java 語言的各個核心主題,旨在幫助你徹底掌握這門強大的編程語言。無論你是想深入理解 Java 的基礎類型與變數作用域,還是探索異常處理與運算子的細節,這些文章都將為您提供寶貴的知識
此外,我們還涵蓋了物件創建、函數式編程、註解應用以及泛型的深入分析,幫助您提升在實際開發中的技能和效率
點擊以下連結,開始你的學習之旅~
● 深入探索 Java 基礎類型、編碼、浮點數、參考類型和變數作用域 | 探討細節
● 深入了解 Java 應用與編譯:從原始檔到命令產出 JavaDoc 文件 | JDK 結構
● 深入理解 Java 運算子與修飾符 | 重要概念、細節 | equals 比較
● 深入探索 Java 物件創建與引用細節:Clone 和finalize 特性,以及強、軟、弱、虛引用
● 認識 Java 函數式編程:從 Lambda 表達式到方法引用 | 3 種方法引用
Java IO 相關文章
● 探索 Java IO 的奧秘,了解檔案操作、流處理、NIO等精彩內容!
深入 Java 多執行緒
● 這一系列文章將帶你深入了解 Java 多執行緒技術的各個方面,從基礎知識到進階應用,涵蓋了多執行緒編程的核心概念與實踐
深入 Java 物件導向
● 探索 Java 物件導向的奧妙,掌握介面、抽象類、繼承等重要概念!幫助你針對物件導向設計有更深入的了解!