classpath、package 和 jar

错误:找不到或无法加载主类

首先给出一个示例:

  1. E:\aaa 目录下创建 A.java

    A.java

    public class A {
    	public static void main(String[] args) {
    		System.out.println("AAA");
    	}
    }
    
  2. 通过 cmd 对 A.java 进行编译

    javac E:\aaa\A.java
    

    这时候在 E:\aaa 目录下生成 A.class

  3. 通过 cmd 运行 A.class (在 E:\aaa 目录下)

    java A
    

    这时候可以运行成功

  4. 通过 cmd 运行 A.class (在 E:\ 目录下)

    这时候会发现运行失败,因为找不到类 A

由 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 类,那我的命令应该是怎样的?如下所示。

  1. 在 E:\bbb\ 目录下创建 B.java

    B.java

    package com.icecoffee.test;
    
    public class B {
    	public static void main(String[] args) {
    		System.out.println("BBB");
    	}
    }
    
  2. 编译 B.java

    javac B.java
    

    在 E:\bbb\ 目录下生成了 B.class 文件,这时候我通过 jd-gui 查看 B.class 文件,发现该文件中并没有源码中的包信息

  3. 在 E:\bbb\ 目录下创建 com\icecoffee\test 多级目录,将 B.class 文件移动到 test 目录下

    这时候通过 jd-gui 再次查看 B.class 文件,发现包信息这行代码又有了,为什么放在对应的包下就有了这行代码,我目前还不知道。

  4. 第一次尝试运行 B.class

    java -classpath E:\bbb B
    

    报错

  5. 第二次尝试运行 B.class

    java -classpath E:\bbb\com\icecoffee\test B
    

    报错

  6. 正确运行 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 显式导入。

猜你喜欢

转载自www.cnblogs.com/cailinfeng/p/12609640.html