Java套件管理(package/import)
Java的套件管理機制主要是透過package與import來完成,使用上相當似於檔案目錄結構的管理方式。利用套件管理機制可以將許多相性質的程式包裝成一個套件,以方面往後的管理與程式的尋找,另外還可以避免許多程式檔名相衝突的情況發生。當你撰寫的程式數量隨著時間不斷的增長時,若平時有養成良好的套件管理習慣,這些程式套件就如同你個人的程式資料庫,在撰寫程式時隨時可以很方便快速的從套件中找出先前寫過的程式來進行重復利用,不必每次都重頭在來過一次,所以每一位學習Java的人都應該了解套件管理的機制與使用方式。
由於Java套件管理是採用檔案目錄的方式,所以在進行以下範例程式時,讀者必須先建立以下的目錄結構,做為本範例的測試環境,以便範例程式能正確的執行。
首先在C:\下建立lattebox目錄做為範例程式的根目錄,接著在底下建立sample目錄並在另外建立兩個子目錄分別為package1與package2,隨後筆者將會此目錄結構來說明Java 套件的運作方式。下圖為詳細的目錄結構:
圖 21 介面範例目錄環境
下表為本範例各程式檔所在的目錄位置與所import的套件來源:
程式 | 所在目錄位置 | 所屬package | import套件 |
---|---|---|---|
PackageA | C:\lattebox\sample\package1 | sample.package1 | 無 |
PackageB | C:\lattebox\sample\package2 | sample.package2 | sample.package1 |
【範例程式】
//PackageA.java 套件範例程式 |
---|
【執行結果】
將上述的範例程式利用javac指令編譯後,再以java指令執行將會發生錯誤如下圖所示:
圖 2-2 程式PackageA執行結果
讀者一定會好奇為何會發生以上的錯誤呢?本範例程式的編譯與執行指令與先前的範例並無不同,既然譯可以通過,而在執行時卻會發生問題,這代表程式的語法並無問題,而問題就是發生在Packet身上。還記得在程式的第一行利用了關鍵字package宣告本程式所在的套件目錄為: sample.package1 ,在java中點號就等同於檔案系統中的目錄分隔符號 / ,所以說PackageA程式所位置應該是位於 sample/package1/PackageA 的目錄結構中,因此在上述的執行錯誤訊息中的第一行 wron anme: sample/package1/PackageA 己明確的告訴我們在這個目錄結構中並找不到PackageA類別。為了深入了解為何會發生找不到類別的情況,就必須先了解Java尋找類別規則。不知讀者是否還記得先前關於java classpath的介紹,在有設定classpath的情況下,java執行時會依照我們給定的位置尋找類別,若無特別設定classpath則預設路徑為執行java指令時所在的目錄位置,但如果我們為類別加入了套件管理機制,類別尋找的規則就必須將套件的路徑一同考慮進去。
未加入套件機制時尋找類別的路徑規則:
classpath路徑\類別名稱 |
---|
加入套件機制後尋找類別的路徑規則:
classpath路徑\套件路徑\類別名稱 |
---|
到目前為止對於packageA會發生找不到路徑的原因己經愈來愈明顯了,我們把上述的規則加以整理後利用圖形表現如下:
圖 2-3 執行時期類別搜尋規則
利用這張圖我們在來重新思考範例PackageA的執行環境,當時由於並沒有指定Classpath路徑因此預設的Classpath會是執行時的目錄位置: C:\lattebox\sample\package1
因為在執行時並無輸入套件名稱,所以套件名稱為空,最後組合出的路徑雖然可以找到PackageA類別,但在驗證時會進行套件路徑檢查,此時套件名稱路徑就會被考慮進去因此Java會認為PackageA類別是位於:
C:\lattebox\sample\package1\sample\package1
但實際上並沒有這個目錄存在,所以就會丟出找不到類別的錯誤訊息。
正確的執行方式應更改為:
C:\lattebox\sample\package1>java -cp C:\lattebox sample.package1.PackageA |
---|
利用-cp(-classpath 縮寫,用法上相同)將路徑設為C:\lattebox,另外需使用類別完整名稱(套件名加類別名),如此一來classpath與套件路徑所組合出的類別路徑就會是: C:\lattebox\sample\package1 類別將可以正確的被找到。另一執方式為直接至套件的根目錄下執行程式,這時就無需設定classpath,因為預設的classpath為“.”,也就是目前所在的執行位置 C:\lattebox。
C:\lattebox>java sample.package1.PackageA |
---|
【執行結果】
圖 2-4 PackageA正確執行結果
說明到這裡相信讀者對package的使用方式己有基本的認識,接著在我們了解如何利用import在程式中使用其它套件中的類。
【範例程式】
//PackageB.java 套件範例程式 |
---|
在PackageB範例中,透過import關鍵字宣告在本程式中所要使用的套件名稱,在使用 PackageA類別時就只需輸入類別名,Java會自動將類別名與import的套件名做組合尋找是否有該類別存在,所以若無使用import在使用PackageB類別時就必須輸入完整的類別名(套件名+類別名) sample.package1.PackageA。使用import並不會影響程式的執行速度,只會程式的編譯時間有影響,所以採用import的方式可以減少程式撰寫的時間與出錯的機會。在撰寫完上述的範例程式後,直接利用javac指令進行編譯:
C:\lattebox\sample\package2>javac PackageB.java |
---|
【編譯結果】
圖 2-5 PackageB編譯結果
此時編譯器告訴我們找import的套件並不存在,這是由於Java會自動的尋找程式中所引用到的類別,若該類別並不存在在進一步尋找原始檔進行編譯,因為我們並沒有特別指定claasspath,因此編譯器自然會找不到PackageA類別檔或原始碼,我們將加入PackageB所在路徑加至classpath中在重新進行編譯,指令如下:
C:\lattebox\sample\package2>javac -cp c:\lattebox\sample\package1;. PackageB.java |
---|
結果依然會發生找不到PackageA,原因很簡單,還記得當類別含有套件名時路徑尋找規則為classpath路徑加上套件路徑嗎?因此在設定classpath時應該指定的是套件的根目錄所在位置,而不是類別實際的所在位置,如此結合出來的路徑才會是正確的c:\lattebox\sample\package1\PackageA 而不是c:\lattebox\sample\package1\sample\package1\PackageA。關於Java編譯規則如下圖所示,Java編譯器會先分析程式原始碼中所引用的類別是否含有套件名稱或是使用import機制,在依情況建立類別路徑搜尋表,而此份搜尋此即為編譯時期尋找類別檔或原始碼的依據。
圖 2-6 Java編譯規則
所以PakcageB程式正確的編譯指令應如下:
C:\lattebox\sample\package2>javac -cp c:\lattebox\;. PackageB.java |
---|
這回總算是可以順利的通過編譯,在執行需注意一樣必須將套件路徑考慮進去,同時需使用完整的類別名稱(套件名加類別名),輸入以下的指令執行:
C:\lattebox>java sample.package2.PackageB |
---|
【執行結果】
圖 2-7 程式PackageB執行結果
透過PackageA與PackageB的範例程式的介紹後,相信讀者己經對Java套件管機制有一定的基礎認識,雖然只利用這兩個簡單的範例並無法完整的函蓋所有套件的運用方式,依然會有許多容易疏忽的使用狀況會造成錯誤,但相信讀者只要能了解根本的運作原理,在遇到其他問題時應該很容易就能找到錯誤的所在。
Android 產訓專班 – Java課程
作者: | Jarey |
---|---|
課程: | 第二堂 物件導向特性 |
內容: |
- 繼承與封裝
- 抽像與介面
多型
|