背景
在寫《【java基礎(四)】hello, world》時,無意遇到的一個問題,對於一個老程序猿在hello, world中遇到的問題卻想不出來一個所以然,所以專門補了補功課。
問題描述
使用記事本編程hello, world,手動javac編譯,java執行。在未使用package時一切正常,使用package後,一下懵了。
問題重現
- 使用記事本編程hello, world
源碼:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello, world");
}
}
- 使用javac編譯,java執行,一切正常。
- 在源碼上使用package。
源碼:
package hello;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello, world");
}
}
- 使用javac編譯,java執行,錯誤重現。
問題解決
從問題現象上來看,很明顯可以看出是package的問題,但是我卻不明白問題出在哪裏,於是尋求答案。
參考文章:解決dos窗口下運行.class文件出現錯誤: 找不到或無法加載主類 HelloWorld
- 解決方法一
去掉package。
- 解決方法二
使用javac -d . HelloWorld.java編譯。
使用java hello.HelloWorld執行。
javac -d . HelloWorld.java
java hello.HelloWorld
深度學習
雖說問題可以解決,但最終還是歸咎與不理解package
關鍵字。於是對package進行補課學習。
參考文章:java初學者,如何理解package和import?
- 以下是對文章的關鍵部分的引用(重點在第5條):
作者:楓亦
鏈接:https://www.zhihu.com/question/278555424/answer/667214584
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
1.java文件通過javac編譯工具編譯變成 class文件。
2.java執行工具可以執行class文件。
3.sourcepath定義了源碼文件搜索的“根路徑”,可以設置多條根路徑。
4.classpath定義了class文件搜索的“根路徑”,可以設置多條根路徑。
5.package關鍵字指明當前源文件和此文件被編譯成class後的文件所在“相對路徑”, package和電腦文件系統的目錄其實是一個意思,比如 com.xx.yy 對應 Linux的 com/xx/yy 對應windows的com\xx\yy。但是注意一個問題,這個路徑是相對的,因爲沒有根,根需要從sourcepath或classpath裏面去找。
比如根 classpath = D:\A;D:\B。
那麼完整的物理路徑就可能是 D:\A\com\xx\yy 也可能是 D:\B\com\xx\yy
所以同屬一個package的源碼文件也即開頭都用了 package com.xx.yy 的源碼文件不一定非要在同一個物理目錄下面。
6.javac編譯過過程中遇到import語句,就會根據 “classpath + 相對路徑”去找 class文件,根據“sourcepath+相對路徑“去找源文件。規則是這樣的:
- 如果只有class文件,就直接用class文件。
- 如果只有源文件,就把源文件編譯成class文件。
- 如果既有class文件又有源文件,就會檢查文件修改的時間戳,如果class文件晚於源文件,就直接用class文件,如果早於源文件,就重新編譯源文件。
另外關於找到的標準要滿足兩條:
- 文件名必須跟類名一樣。
- 文件裏面package定義的相對路徑必須和import定義的相對路徑一樣。
7.簡單說一下class文件,前面提到的相對路徑信息在源碼中是package關鍵字指明的,class文件中也有這些信息,只不過不是在文件頭部指明,而是直接內化成類全稱了,看個例子:
源碼:
package A;
public class Hello{
public static void main(String args[]){
System.out.println("Hello World!");
}
}
class文件 反編譯效果:
public class A.Hello {
public A.Hello();
public static void main(java.lang.String[]);
}
注意 Hello類直接變成了 A.Hello,也就是類名稱自動包含了路徑信息。
8.java執行class文件時,遇到 如new、getstatic 等等需要創建類實例的相關指令時,就會加載相關的class文件(也稱動態加載),那麼jvm會去哪裏找class文件呢?跟javac類似還是通過“classpath + 相對路徑”去找。
9.jar文件就是把class文件以及相對目錄結構打包而成的文件,感興趣可以直接解壓看看。
思考
跟同年出道的朋友討論此問題,發現對package一樣的懵。我感覺產生這種問題的原因是:
- 太過於依賴IDE。這也不能是一種錯誤,畢竟IDE帶來的便利性是沒有辦法替代的。
- 基礎不紮實。很多問題都不喜歡追究溯源,只是到了解決問題的步驟就可以了。
- 意想(瞎想)問題原因。我感覺這是現在人們的通病,自己本身不知道問題出在那裏,單純的根據現象猜測出現問題的原因,並且說的理直氣壯,其實根本沒有理論的支撐。就好像我朋友說這個問題是由於“引入了不存在的包”,這種“不存在的包”這種詞語就屬於意想出來的。
- 不理解本質。想package的感念,很多人都理解爲和文件目錄一樣,我感覺你可以這樣理解package,但不可以把package和文件目錄劃等號,更好的理解應該是命名空間(本人能力有限,嘴皮也有限,不多陳述)。
捐贈
若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。