1. 程式人生 > >main class not found error

main class not found error

編譯時要打上.java字尾

執行時不要,只用檔名就行

修改完環境變數後 要用source /etc/profile 使修改立刻生效,否則跟沒改一樣

類路徑(classpath)

java編譯器編譯.java檔案和java虛擬機器執行.class檔案時的路徑和寫法不一樣。

在沒有設定任何classpath環境變數的情況下,javac可以編譯全路徑的.java檔案。例如:

編譯後,在.java同路徑目錄下生成class檔案。

預設java虛擬機器要從classpath環境變數的路徑中搜索class檔案去執行,對於java虛擬機器來說,這不是類檔案,而是類。它只有類路徑,而沒有檔案系統路徑。而classpath環境變數正是為java虛擬機器提供搜尋類路徑的環境。注意,虛擬機器不會遞迴搜尋classpath定義的路徑。

也就是說,上面的java檔案可以正確編譯,但卻不能執行。但如果將classpath設定為".;d:\myjava\",則java虛擬機器將從當前路徑搜尋,從d:\myjava下搜尋class檔案。

於是上面的HelloWorld.java編譯後,可以直接執行:

或者切換到d:\myjava目錄下,執行java HelloWorld

但下面則是錯誤的方式,最後雖然能正確編譯NewDir.java,但在執行時,將搜尋當前目錄(d:\myjava)下是否有NewDir.class,再搜尋d:\myjava下是否有NewDir.class,但不會遞迴到子目錄newdir中去搜索class檔案。

再例如,在d:\myjava\hello下有兩個java原始檔,它們的內容分別如下:

其中Dog類中直接new了另一個檔案中Cat類的物件,無論是編譯還是執行,這都是能成功的,因為javac編譯器編譯Dog.java時會自動從classpath指定的路徑下搜尋Cat.class,正好這能搜尋到,且該類又是public類,因此編譯成功。

總之,要明確的是javac編譯器搜尋的是檔案路徑,和環境變數classpath無關。而java虛擬機器搜尋的是類檔案,嚴格地說是類,搜尋路徑由環境變數classpath決定,且有先後順序。

更多的類路徑說明,見下面的"包"。

包(package)

包是類的集合。在java原始檔的第一行(不包括註釋行或空行)寫上package關鍵字並給定包名,即可將該類檔案放到包中。

例如,d:\myjava\Cat.java檔案:

這表示將Cat類放在com.longshuai.home包中。包應該以反轉後的域名取名,防止包重名衝突,當然,這是非必須的。

對於沒有使用package指令的原始檔,在編譯時其內的類都會預設當作"裸體類"。

java管理包的方法是以對應包名的目錄層次管理的,例如上面的com.longshuai.home包,應該將該class檔案放在com/longshuai/home(如果是windows,則反斜線)下,即com/longshuai/home/Cat.class。

javac在編譯時從路徑上搜索檔案。例如,將這個Cat.java放到com/longshuai/home下。執行時java虛擬機器從classpath搜尋要載入的類檔案,而載入類的方式是使用"."連線各類名。所以編譯這個檔案和java虛擬機器執行這個檔案時的方法分別是:

注意,巢狀的包之間沒有任何關係,例如java.util包和java.util.jar包沒有任何依賴關係。

使用包中的類和匯入包(import)

在某個java原始檔中,無法直接使用其他檔案中的類,除非要使用的這個類正好能被classpath的路徑搜尋到。要引用非classpath下的其他類,只能將其新增到classpath或者裝入package中,然後引用包中的類。

引用包中類可以通過指定包名的方式引用來引用。例如:

但顯然這很不方便。可以在java原始檔的前幾行(但在package命令的後面)使用import指令匯入需要使用的包中的類。例如匯入Cat類,這樣就可以直接使用該類了:

匯入包時可以在尾部使用星號"*"通配匯入的所有類,只能在尾部使用"*",因為"*"匹配的是類名,而不是包名。也因此,不能在非結尾處使用"*"號來表示匯入其他包中的類,例如:

如果匯入的包中有同名的類,則在引用同名類的時候會產生衝突錯誤,例如java.util和java.sql包中都有Date類,

編譯:

這時可以顯式匯入Date類,或者在使用Date類的時候指定包名。也就是說下面兩種方法都正確:

除了可以匯入包中的類,還可以靜態匯入包中類中的靜態方法和靜態變數,只需加上static關鍵字並指定要匯入的內容即可。例如:

靜態匯入方法後,就可以省略字首,例如:

將package歸檔成jar包

java虛擬機器可以直接識別jar包。可以將package名稱對應的路徑使用jar命令歸檔成jar包。jar命令使用說明如下:

例如,將當前目錄下的a.class和b.class打包到test.jar中:

檢視jar包中的檔案列表,會遞迴顯示:

例如,將com目錄歸檔到d:\dp.jar中。

有了jar檔案,就可以直接設定classpath的路徑為jar檔名,這樣在搜尋類檔案時就會直接從jar檔案內搜尋。例如classpath設定為:

類搜尋機制

在java虛擬機器搜尋類檔案時,除了classpath環境變數指定的路徑,還會先搜尋兩個預設的路徑:jre/lib和jre/lib/ext下的jar檔案中似乎否有待搜尋的類。

例如,當classpath設定為".;d:\myjava;d:\myjar.jar"時,要搜尋com.longshuai.com.Cat類檔案: (a).先搜尋jre/lib和jre/lib/ext下的jar檔案; (b).再搜尋當前目錄下是否有com\longshuai\com\Cat.class; (c).再搜尋d:\myjava\Cat.class; (d).搜尋d:\myjar.jar檔案中是否有com.longshuai.com.Cat類。 

如果在某個java原始檔中引用了某個類,則在編譯時,將通過以下幾種方式判斷該類是否合理有效:

(1).搜尋匯入的包類中是否包含該類。 (2).搜尋隱式匯入的java.lang包,該包是預設匯入的。 (3).當前檔案中是否定義了該類。 (4).按照類路徑的搜尋規則((a)-(d))搜尋其中是否有該類。 

繼承

類與類之間能體現"什麼是什麼"的語義邏輯,就能實現類的繼承。例如,貓是動物,那麼貓類可以繼承動物類,而貓類稱為子類,動物類稱為父類。

子類繼承父類後,子類就具有了父類所有的成員,包括成員變數、方法。實際上在記憶體中,new子類物件時,heap中劃分了一部分割槽域存放從父類繼承來的屬性。例如,new parent得到的區域A,new child得到的區域B,區域A在區域B中。

子物件中之所以包含父物件,是因為在new子物件的時候,首先呼叫子類構造方法構造子物件,在開始構造子物件的時候又首先呼叫父類構造方法構造父物件。也就是說,在形成子物件之前,總是先形成父物件,然後再慢慢的補充子物件中自有的屬性。具體內容見"繼承時構造方法的重寫super()"。

子類不僅具有父類的成員,還具有自己獨有的成員,例如有自己的方法、自己的成員變數。子類、父類中的成員名稱不同時這很容易理解,但它們也可能是同名的。如果子類中有和父類繼承的同名方法,例如父類有eat()方法,子類也有eat()方法,則這可能是方法的重寫(見下文)。如果子類中的成員變數和父類的成員變數同名,則它們是相互獨立的,例如父類有name屬性,子類還自己定義了一個name屬性,這是允許的,因為可以分別使用this和super來呼叫它們。

繼承類時使用extends關鍵字。繼承時,java只允許從一個父類繼承。