阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

classpath和jar

79次阅读
没有评论

共计 2726 个字符,预计需要花费 7 分钟才能阅读完成。

在 Java 中,我们经常听到 classpath 这个东西。网上有很多关于“如何设置 classpath”的文章,但大部分设置都不靠谱。

到底什么是classpath

classpath是 JVM 用到的一个环境变量,它用来指示 JVM 如何搜索class

因为 Java 是编译型语言,源码文件是 .java,而编译后的.class 文件才是真正可以被 JVM 执行的字节码。因此,JVM 需要知道,如果要加载一个 abc.xyz.Hello 的类,应该去哪搜索对应的 Hello.class 文件。

所以,classpath就是一组目录的集合,它设置的搜索路径与操作系统相关。例如,在 Windows 系统上,用 ; 分隔,带空格的目录用 "" 括起来,可能长这样:

C:\work\project1\bin;C:\shared;"D:\My Documents\project1\bin"

在 Linux 系统上,用 : 分隔,可能长这样:

/usr/shared:/usr/local/bin:/home/liaoxuefeng/bin

现在我们假设 classpath.;C:\work\project1\bin;C:\shared,当 JVM 在加载 abc.xyz.Hello 这个类时,会依次查找:

  • < 当前目录 >\abc\xyz\Hello.class
  • C:\work\project1\bin\abc\xyz\Hello.class
  • C:\shared\abc\xyz\Hello.class

注意到 . 代表当前目录。如果 JVM 在某个路径下找到了对应的 class 文件,就不再往后继续搜索。如果所有路径下都没有找到,就报错。

classpath的设定方法有两种:

在系统环境变量中设置 classpath 环境变量,不推荐;

在启动 JVM 时设置 classpath 变量,推荐。

我们强烈 不推荐 在系统环境变量中设置 classpath,那样会污染整个系统环境。在启动 JVM 时设置classpath 才是推荐的做法。实际上就是给 java 命令传入 -classpath 参数:

java -classpath .;C:\work\project1\bin;C:\shared abc.xyz.Hello

或者使用 -cp 的简写:

java -cp .;C:\work\project1\bin;C:\shared abc.xyz.Hello

没有设置系统环境变量,也没有传入 -cp 参数,那么 JVM 默认的 classpath.,即当前目录:

java abc.xyz.Hello

上述命令告诉 JVM 只在当前目录搜索Hello.class

在 IDE 中运行 Java 程序,IDE 自动传入的 -cp 参数是当前工程的 bin 目录和引入的 jar 包。

通常,我们在自己编写的 class 中,会引用 Java 核心库的 class,例如,StringArrayList 等。这些 class 应该上哪去找?

有很多“如何设置 classpath”的文章会告诉你把 JVM 自带的 rt.jar 放入classpath,但事实上,根本不需要告诉 JVM 如何去 Java 核心库查找class,JVM 怎么可能笨到连自己的核心库在哪都不知道!

注意

不要把任何 Java 核心库添加到 classpath 中!JVM 根本不依赖 classpath 加载核心库!

更好的做法是,不要设置 classpath!默认的当前目录. 对于绝大多数情况都够用了。

假设我们有一个编译后的Hello.class,它的包名是com.example,当前目录是C:\work,那么,目录结构必须如下:

C:\work
└─ com
   └─ example
      └─ Hello.class

运行这个 Hello.class 必须在当前目录下使用如下命令:

C:\work> java -cp . com.example.Hello

JVM 根据 classpath 设置的 . 在当前目录下查找 com.example.Hello,即实际搜索文件必须位于com/example/Hello.class。如果指定的.class 文件不存在,或者目录结构和包名对不上,均会报错。

jar 包

如果有很多 .class 文件,散落在各层目录中,肯定不便于管理。如果能把目录打一个包,变成一个文件,就方便多了。

jar 包就是用来干这个事的,它可以把 package 组织的目录层级,以及各个目录下的所有文件(包括 .class 文件和其他文件)都打成一个 jar 文件,这样一来,无论是备份,还是发给客户,就简单多了。

jar 包实际上就是一个 zip 格式的压缩文件,而 jar 包相当于目录。如果我们要执行一个 jar 包的 class,就可以把 jar 包放到classpath 中:

java -cp ./hello.jar abc.xyz.Hello

这样 JVM 会自动在 hello.jar 文件里去搜索某个类。

那么问题来了:如何创建 jar 包?

因为 jar 包就是 zip 包,所以,直接在资源管理器中,找到正确的目录,点击右键,在弹出的快捷菜单中选择“发送到”,“压缩 (zipped) 文件夹”,就制作了一个 zip 文件。然后,把后缀从 .zip 改为.jar,一个 jar 包就创建成功。

假设编译输出的目录结构是这样:

package_sample
└─ bin
   ├─ hong
   │  └─ Person.class
   │  ming
   │  └─ Person.class
   └─ mr
      └─ jun
         └─ Arrays.class

这里需要特别注意的是,jar 包里的第一层目录,不能是bin,而应该是hongmingmr。如果在 Windows 的资源管理器中看,应该长这样:

classpath 和 jar

如果长这样:

classpath 和 jar

说明打包打得有问题,JVM 仍然无法从 jar 包中查找正确的 class,原因是hong.Person 必须按 hong/Person.class 存放,而不是bin/hong/Person.class

jar 包还可以包含一个特殊的 /META-INF/MANIFEST.MF 文件,MANIFEST.MF是纯文本,可以指定 Main-Class 和其它信息。JVM 会自动读取这个 MANIFEST.MF 文件,如果存在Main-Class,我们就不必在命令行指定启动的类名,而是用更方便的命令:

java -jar hello.jar

在大型项目中,不可能手动编写 MANIFEST.MF 文件,再手动创建 zip 包。Java 社区提供了大量的开源构建工具,例如 Maven,可以非常方便地创建 jar 包。

小结

JVM 通过环境变量 classpath 决定搜索 class 的路径和顺序;

不推荐设置系统环境变量 classpath,始终建议通过-cp 命令传入;

jar 包相当于目录,可以包含很多 .class 文件,方便下载和使用;

MANIFEST.MF文件可以提供 jar 包的信息,如Main-Class,这样可以直接运行 jar 包。

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2726字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中