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的问题,但是没有说透,写的太繁琐了。
三、fire in the hole
我大概明白了我的代码运行错误的原因了。常常用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