1. 程式人生 > 其它 >javac學習-“Error: Could not find or load main class Main”

javac學習-“Error: Could not find or load main class Main”

技術標籤:Java基礎JAVAjvmjava

javac學習-“Error: Could not find or load main class Main”

一、上報錯程式碼

package hello;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

編譯後,執行報錯

$ javac HelloWorld.java
$ java HelloWorld
Error: Could not find
or load main class HelloWorld

二、查詢問題

2.1 查詢java入門的程式碼示例

百思不得其解,到線上學習java的網站上看了下程式碼,我的程式碼只是多了package,難道是這個產生的這個問題嗎?

示例程式碼

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
$ javac HelloWorld.java
$ java HelloWorld
Hello World

也給網站上加一個package,一樣報錯。

Error: Could not find or load main class Main
Caused by: java.lang.NoClassDefFoundError: hello/Main (wrong name: Main)

Exited with error status 1

2.2 csdn文章大佬分享

在一個csdn的帖子裡說到了classpath的問題,但是沒有說透,寫的太繁瑣了。但是給的一個連結對classpath的介紹說的很好。

csdn 帖子:https://blog.csdn.net/abcdu1/article/details/86693800

stackover帖子:https://stackoverflow.com/questions/18093928/what-does-could-not-find-or-load-main-class-mean

這個stackover帖子很清晰的羅列了包羅永珍的java編譯出錯的原因。

答案可能在其中,但是我沒有得到很清晰的答案,繼續上下而求索。

三、fire in the hole

最後在百度的知道里找到很直接很暴力的答案 (百度知道很難得提供了正確的資訊)。

https://zhidao.baidu.com/question/213065551.html

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-b2dyJNQ0-1607748802719)(…/image/image-20201212115120286.png)]

這裡清晰的說出了,如果有package,那麼你的java檔案所在的目錄結構就要和package對應

我大概明白了我的程式碼執行錯誤的原因了。常常用idea intellij搬磚,已經忘記了來的路了。其實intellij軟體會根據我們命名的package,建立對應的目錄,包括編譯出的class檔案的路徑也是按照這個結構。

對照著分析著裸奔的java程式碼和工程裡的java檔案路徑,猜測java在執行程式碼的時候,package和目錄應該這都是要一一對應的。查看了大佬關於jvm中的說明,並提到了“雙親委派機制”中的過程。jvm中照這個package,轉換成目錄來查詢class的

classpath只是一個基點,package是以classpath的相對路徑。

以下是URLClassLoader.java中的部分程式碼。

/* The search path for classes and resources */
private final URLClassPath ucp;

protected Class<?> findClass(final String name)
  throws ClassNotFoundException
{
  final Class<?> result;
  try {
    result = AccessController.doPrivileged(
      new PrivilegedExceptionAction<Class<?>>() {
        public Class<?> run() throws ClassNotFoundException {
          String path = name.replace('.', '/').concat(".class");
          Resource res = ucp.getResource(path, false);
          if (res != null) {
            try {
              return defineClass(name, res);
            } catch (IOException e) {
              throw new ClassNotFoundException(name, e);
            }
          } else {
            return null;
          }
        }
      }, acc);
  } catch (java.security.PrivilegedActionException pae) {
    throw (ClassNotFoundException) pae.getException();
  }
  if (result == null) {
    throw new ClassNotFoundException(name);
  }
  return result;
}

四、測試

於是我新建了hello目錄,將HelloWorld.java扔入其中,不進去hello目錄,執行編譯和執行的命令。

$ mkdir hello
$ mv HelloWorld.java hello
$ javac hello/HelloWorld.java 
$ java hello.HelloWorld
Hello World

$ rm HelloWorld.class 
$ java hello.HelloWorld
Hello World

$ java hello/HelloWorld
Hello World

結果顯示正確。

打算繼續測試-cp和package的關係,進入hello目錄,再試了一下

$ cd hello/
$ java HelloWorld
Error: Could not find or load main class HelloWorld

$ java -cp ../ hello/HelloWorld
Hello World

$ javac HelloWorld.java 
$ java -cp ../ hello/HelloWorld
Hello World

$ java -cp ./ hello/HelloWorld
Error: Could not find or load main class hello.HelloWorld

$ java HelloWorld
Error: Could not find or load main class HelloWorld

五、結論

通過以上測試,當代碼中有指定package時,有幾點需要注意的:

5.1 目錄結構和package要對應

目錄結構和package要對應,如 package hello,就一定更要把class檔案放在hello目錄下

5.2 在執行的時候一定要帶上全稱:package + 類名

如:hello/HelloWorld 或 hello.HelloWorld

5.3 classpath路徑問題

classpath不指定,預設表示是當前資料夾,在有package的情況下,一定要可以通過classpth + package找到你要執行的class-cp表示指定classpath路徑

​ (1)如果和class檔案在同一目錄,那麼就要把classpath改寫到上一級目錄:

​ java -cp …/ hello/HelloWorld

​ (2)如果和class檔案同一個目錄,可以

​ java -cp ./ hello/HelloWorld

​ (3)並且,因為是同一目錄,可以省略-cp,

​ java hello/HelloWorld