1. 程式人生 > >Java:windows shell 下package和import的問題:類放在同一包下為什麼顯示cant find symbol?

Java:windows shell 下package和import的問題:類放在同一包下為什麼顯示cant find symbol?

使用cmd或者powershell執行java注意事項

不使用IDE時,我們編寫多個java檔案後想要編譯並測試執行的話,需要注意一些問題
對於執行入口的App.java或者測試XXTest.java而言,需要cmd在根package目錄的上一級目錄下執行
比如你要寫一個軟體,myapp,建立了根目錄myapp,編寫的所有類檔案都在myapp內
軟體入口App.java位於 myworkspace\myapp\App.java
在保證myapp下所有類的import和package以myapp為根命名時
編譯此檔案,cmd的訪問位置必須是:myworkspace > javac myapp/App.java

cmd訪問方式產生的問題

如果在App.java當前或者其他目錄按相對路徑訪問java檔案,比如

myworkspace\myapp> javac App.java 
F:> javac myworkspace\myapp\App.java

問題:

如果App.java有非同檔案下的依賴類:
編譯器報cant find symbol 錯誤

原因:

是cmd下編譯java檔案,當前類需要某個外部依賴類位元組碼時,
1. 寫了package沒寫import
編譯器讀取package標識,按照其路徑,在cmd位置,向下掃描依賴類
1-1. 如果找到依賴類,訪問class檔案,讀取package標識,標識為同包即找到該依賴類 OK!


1-2. 如果找到依賴類,訪問class檔案,讀取package標識,標識為不同包即未找到
如果2)始終找不到package標識相同的依賴類class檔案,顯示錯誤,cant find symbol,bad class file

2. 寫了import,或標識了類字首
如果1中過程沒找到依賴類,編譯器就讀取import標識和字首,按照其路徑,在cmd位置,向下掃描依賴類,
後面具體過程和1-11-2相同

顯然,按照java規範,cmd如果不在根package上一級目錄,執行編譯,那麼肯定找不到依賴類(import配置過環境變數的java classpath除外),相反就是package與import命名不規範。

舉個不同包(2個類package命名不同,或不在一個實體地址目錄下)的例子

情景
假設我們有2個java檔案 App.java(未編譯) Dependency.java(已編譯),App繼承Dependency,或呼叫其靜態欄位和方法
設package根目錄為\app 實體地址c: \home\app
Dependency目錄: \app\dependency 即Dependency.java註明 package app.dependency;
App目錄: \app 即App.java註明 package app; import app.dependency.Dependency;

此時假設cmd在\app執行
c:\home\app > javac App.java
顯示錯誤: cant find symbol;描述原因:package app.app.dependency不存在;按照import app.dependency.*找不到Dependency.class;

過程描述:編譯器讀取了App.java,先按照App所在包package app; ;以c:\home\app為當前位置,向下查詢\app資料夾看是否有Dependency.class,發現c:\home\app\app不存在。
然後啟動import,按照import app.dependency.Dependency; ,查詢c:\home\app\app\dependency\Dependency.class,發現不存在

解決方法:cmd在package根目錄上一級執行編譯即可。

注意這裡有個trick,類的package命名同包,但是實體地址不在一個目錄下,雖然實際上類不同包,但可以不用import訪問依賴類,如下:

設package根目錄為\app 實體地址c: \home\app
Dependency目錄: \app\dependency Dependency.java註明 package app.dependency; 違反規範!
App目錄: \app 即App.java註明 package app.dependency;
此時假設cmd在app上一級目錄執行javac編譯App.java,
App可以訪問Dependency的公開欄位和方法,且不用寫import
但是對於保護欄位和方法就不行,系統會顯示Exception in main thread trying to access protected field,即使是“同名的包”