错误:找不到或无法加载主类
首先给出一个示例:
-
在
E:\aaa
目录下创建 A.javaA.java
public class A { public static void main(String[] args) { System.out.println("AAA"); } }
-
通过 cmd 对 A.java 进行编译
javac E:\aaa\A.java
这时候在 E:\aaa 目录下生成 A.class
-
通过 cmd 运行 A.class (在 E:\aaa 目录下)
java A
这时候可以运行成功
-
通过 cmd 运行 A.class (在 E:\ 目录下)
这时候会发现运行失败,因为找不到类 A
扫描二维码关注公众号,回复: 10356490 查看本文章
由 3 和 4 的对比我们可以得出结论,java 命令执行时,是在当前目录下查找类,不会递归查找当前目录下的子目录,如果在当前目录下找不到类,就会发生错误。
如果我就是想在 E:\ 目录下运行 E:\aaa\ 目录下的 class 文件,怎么做呢?这就需要用到 classpath 这个选项了。
classpath
在 cmd 中执行 java -help
可以看到关于 classpath 这个选项的官方说明(也包括其他的选项的说明)
这个命令就是用于搜索类文件的,这正是我们想要的。
格式为:
java -classpath 类路径 类名
类路径可以有多个,用
;
分隔,不需要以;
结尾
于是,按照说明,在 E:\ 目录下,我将 classpath 命令加上:
java -classpath E:\aaa A
运行成功!
这时候我们结合第二部分 classpath 来看,可以明白为什么我们在当前目录下执行 java 命令运行 class 文件是没问题的。因为我们在执行 java 命令时,实际上执行时会将当前目录作为参数加入。
即,我们在执行 java A
时,实际上执行的命令是 java -classpath . A
,其中 .
表示当前目录。
package
上述的只是一个简单的类,A 类不属于任何一个包,在实际中我们都会将类放入包中,就像将一个大柜子分成很多小格子,这样便于我们的查找。一般包名都是以公司域名的反写命名,类似 com.icecoffee
这样。
Java 的多级包在文件系统中都是以多级文件夹的形式存在,如com.icecoffee.test
对应到文件系统中就是 com\icecoffee\test
这样的多级文件夹。既然如此,那就让我开始疑惑了,如果我们想运行一个 com.icecoffee.test
包下的 B 类,那我的命令应该是怎样的?如下所示。
-
在 E:\bbb\ 目录下创建 B.java
B.java
package com.icecoffee.test; public class B { public static void main(String[] args) { System.out.println("BBB"); } }
-
编译 B.java
javac B.java
在 E:\bbb\ 目录下生成了 B.class 文件,这时候我通过 jd-gui 查看 B.class 文件,发现该文件中并没有源码中的包信息
-
在 E:\bbb\ 目录下创建 com\icecoffee\test 多级目录,将 B.class 文件移动到 test 目录下
这时候通过 jd-gui 再次查看 B.class 文件,发现包信息这行代码又有了,为什么放在对应的包下就有了这行代码,我目前还不知道。
-
第一次尝试运行 B.class
java -classpath E:\bbb B
报错
-
第二次尝试运行 B.class
java -classpath E:\bbb\com\icecoffee\test B
报错
-
正确运行 B.class 的命令
java -classpath E:\bbb com.icecoffee.test.B
由 4、5、6 这三次命令的对比,我们可以得出当要运行的类位于某个包下,正确的命令是将最外层包所在的目录作为 classpath 的参数,类名前面需要加上多级包,即类名需要写成全限定类名的方式。在这其中,第 5 步我尝试将多级包包含于 classpath 的参数中进行运行,事实证明是行不通的。
jar
jar 包就是将多个 class 文件打成一个压缩包,.jar 文件可以通过压缩软件打开查看。
在 cmd 中通过 jar -help
可以查看 jar 命令的相关用法
现在我将第三部分 package 的 B.class 文件打成一个 jar 包
在 E:\bbb\ 目录下,执行:
jar cvf B.jar com
com 表示所要打包的目录,因为 B.class 属于
com.icecoffee.test
这个包,所以最外层的包是 com,jar命令会对该目录递归执行
压缩成功后会在当前目录下生成一个 B.jar 的压缩文件。
我们同样可以直接运行 jar 包中的 B.class
java -classpath E:\bbb\B.jar com.icecoffee.test.B
运行成功!
另外,需要知道的是,在执行 java 命令时,除了 classpath 的参数外,JVM 还会先去 jre\lib 和 jre\lib\ext 这两个默认目录下搜索类,这也是为什么我们在导入了 JDK 中除了 java.lang
包之外的类就可以编译运行的原因。
比如,java.util.Date
这个类就位于 jre\lib 目录下的 rt.jar 这个包中
为什么是除了 java.lang
包之外呢?因为这个包中的类非常常用,几乎每个自定义类中都需要用到这个包中的类,比如 String
。所以这个包中的所有类都是隐式导入的,不需要在 java 文件中通过 import
显式导入。