2013-07-15 102 views
1

我最近開始學習Java,但是我遇到了一些與NoClassDefFoundError有關的問題。我試圖從這個網站和其他地方研究解決方案,但仍然無法解決它們。我使用CLASSPATH環境變量集從Windows 7命令提示符運行我的程序,而不是爲每個程序運行定義它。它設置爲C:。爲了排除故障,我創建了一個簡化目錄結構的測試包。帶繼承類的Java NoClassDefFoundError

C:\test,我有Shape.javaCircle.javaShape.java看起來是這樣的:

package test; 

class Shape { 
    void draw() { System.out.println("Drawing a new shape"); } 
} 

Circle.java看起來是這樣的:

package test; 

public class Circle extends Shape { 
     public static void main(String[] args) { 
     Circle round = new Circle(); 
     round.draw(); 
    } 
} 

如果我在與操作命令提示符像

C:\>javac test\Shape.java 
C:\>javac test\Circle.java 

和編譯都Shape.javaCircle.javaC:\運行編譯的Circle.class文件,如

C:\java test\Circle 

我得到的輸出我想到:

Drawing a new shape 

但是,如果我編譯從C:\test

C:\test>javac Shape.java 
C:\test>javac Circle.java 

Shape.javaCircle.java,然後嘗試從任何地方像運行Circle.class

C:\test>java Circle 

或類似這樣的

C:\> java test\Circle 

我收到以下錯誤消息。

Exception in thread "main" java.lang.NoClassDefFoundError: Circle (wrong name: t 
est/Circle) 
     at java.lang.ClassLoader.defineClass1(Native Method) 
     at java.lang.ClassLoader.defineClass(ClassLoader.java:792) 
     at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:14 
2) 
     at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) 
     at java.net.URLClassLoader.access$100(URLClassLoader.java:71) 
     at java.net.URLClassLoader$1.run(URLClassLoader.java:361) 
     at java.net.URLClassLoader$1.run(URLClassLoader.java:355) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at java.net.URLClassLoader.findClass(URLClassLoader.java:354) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:424) 
     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) 
     at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 
     at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482) 

有人能解釋爲什麼它是在JAVA文件從C:\test文件夾中編譯,但編譯後的文件圈產生錯誤?我的CLASSPATH有問題嗎?感謝您的閱讀和希望即將到來的解決方案!

編輯:我做更多的測試,事實證明,如果我編譯從C:\test目錄Shape.javaCircle.java文件,但是從C:\目錄中運行它,它的工作原理。這會改變什麼嗎?

編輯2:經過更多的測試後,事實證明,我可以事實上編譯並運行C:\ test目錄下的Shape.java和Circle.java文件,只要我使用命令java test.Circle 。我誤解了JVM尋找類的方式。我現在明白它在分析包導入語句時使用與編譯器相同的方法。

+0

使用eclipse工作臺。 – Makky

+0

使用'java test.Circle' –

+0

您應該認真使用像Eclipse這樣的IDE。 –

回答

1

只要你有一個類路徑,你可以在系統的任何地方。

只有這樣,java VM才能夠掃描類路徑,並找到包test中的類test.Circle

所以,正確的執行是java test.Circle(總是),並且類路徑需要指向可能有\test\Circle.class的東西。檢查Circle.class是否您期望它。

+0

+1 - 要確定(基本上你正確地描述了它):類路徑需要指向本身包含'test'目錄(=包)的目錄 - 例如如果'test.Circle'類位於'c:\ bin \ test \ Circle.class'中,那麼類路徑需要指向'c:\ bin' –

+0

非常感謝這樣的快速回復!我的Shape.class和Circle.class文件都在C:\ test目錄中創建。 classpath是什麼意思?如果我的類路徑設置爲C:\,並且test \ Circle.class可用,那麼編譯和運行Circle.class文件的目錄是否會有所不同? – user2582713

+0

我的意思是綁定c-kolon-backslash,但我認爲編輯器省略了我的擊鍵:)無論如何,正如Andreas所闡明的那樣,classpath是搜索樹根的集合。無論它是在目錄內,在zip文件(或jar文件)中,還是從網絡url中。這是類加載器'魔術' –

0

您的類路徑代表您存儲類的位置。因爲您已將類路徑設置爲c:\。因此,當您使用java命令啓動jvm時,它將加載所需的類形式c:\。當你編譯並運行程序C:時,你的代碼正在工作,因爲這些類將被編譯,並且在那種情況下將出現在C:中,所以沒有問題。但是當你從c:\test編譯你的類時,你的.class文件將出現在c:\ test中,但是你的類路徑只會加載類c:\而不是c:\test

+0

非常感謝您的回覆。這是否意味着,作爲一般規則,我應該只從類路徑目錄編譯和運行我的程序? – user2582713

+0

您需要將編譯好的類與適當的包結構放在類路徑中。或者,您可以隨時將當前目錄添加到類路徑中。一旦你在classpath中擁有你的類,那麼你可以從任何地方運行它。 –

+0

但是正在C:\ test目錄中生成Shape.class和Circle.class文件。這是不正確的包裝結構? – user2582713

0

編譯,使用

javac -d . Shape.java 
javac -d . Circle.java 

運行

java test.Circle 

-d是選擇目標目錄
.意味着當前目錄 因此,在當前的直供C:\test\當您編譯, java文件,將創建一個名爲test(包名稱)的新目錄,並在其中包含類文件。 即。
C:\test\test\Shape.javaC:\test\test\Circle.java

+0

它工作!你能解釋爲什麼當我從C:\ test目錄內編譯Shape.java和Circle.java文件時,編譯器不會自動創建C:\ test \ test目錄嗎? – user2582713

+0

@ user2582713如果有效,您可以通過點擊我答案左側的勾號來接受答案。您的評論的答案很明顯,我們希望在當前目錄中生成類文件,但我不能給你確切的解釋。如果你願意的話,你可以把它作爲一個新問題。 –

+0

-d。是默認值。真正的意義在於從包結構的頭部進行編譯,而不是源文件所在的目錄。 – EJP