或多或少,我们都会见到用这两种命令启动java程序,最基本的用法如:

java [options] -jar xxx.jar [args]
java [options] -cp xxx.jar classname [args]

那这两种用法有什么区别呢?

我们先写一个简单的测试类(为了方便说明问题,不借助开发工具):

1)在本机随便找个目录,创建com.test目录,并编写HelloTest.java文件:

cp java 路径 java -cp命令详解_jar

package com.test;

public class HelloTest {

	public static void main(String[] args) {
		String name = args[0];
		System.out.println("hello:"+name);
	}
}

2)编译:

cp java 路径 java -cp命令详解_cp java 路径_02

3)打jar包:

cp java 路径 java -cp命令详解_jar_03

 4)我们尝试用最开始说的两种命令来执行

cp java 路径 java -cp命令详解_jar包_04

 发现-jar命令执行的结果提示:没有主清单属性,什么意思呢?

首先说下jar包,jar包跟我们通常认知的.zip压缩文件,是一样一样的,我们甚至完全可以用普通zip压缩工具来压缩com目录,然后用java -cp com.zip com.test.HelloTest everybody照样能运行,不同的是,用jar命令打出的jar包会多出来一个东西:

cp java 路径 java -cp命令详解_cp java 路径_05

看到没,一个META-INF目录,里面有一个文件:MANIFEST.MF,其内容如下:

Manifest-Version: 1.0
Created-By: 1.8.0_171 (Oracle Corporation)

这个文件就是jar的清单文件,可以理解成一个标识配置文件,上面说的java -jar执行结果提示:没有主清单属性,就是因为我们的清单文件中少了一样属性,这个属性是:Main-Class,它声明了jar包的默认入口类,也是java -jar运行时开始执行的类,其格式为:

Main-Class: com.test.HelloTest

我们把test.jar解压后,在MANIFEST.MF文件中加入该属性:

cp java 路径 java -cp命令详解_cp java 路径_06

 然后用.zip格式直接再次压缩后(命名为test2.jar),执行java -jar test2.jar

cp java 路径 java -cp命令详解_java_07

 注意:清单属性配置格式问题,冒号后面需要一个空格,否则会报Error: Invalid or corrupt jarfile错误,属性结束必须换行,否则仍然找不到属性

当然,实际上也不需要如此麻烦,我们在打jar包时可以通过-e参数指定默认入口,会自动生成Main-Class属性,此时jar包就是一个可执行jar文件:

cp java 路径 java -cp命令详解_jar包_08

 用java -jar运行jar包时,虚拟机忽略系统中的classpath配置,如果有依赖jar,需要在清单属性中指定,格式为:

Class-Path: servlet.jar infobus.jar acme/beans.jar

多个jar包之间用空格隔开,其位置是相对于当前运行的jar包所在的目录;

用java -cp运行时,其cp本身就是classpath的意思,对于多个依赖的jar格式为:

java -cp test.jar;test1.jar;test2.jar com.test.HelloTest

注意:jar包之间的分隔符在windows上是分号";",而在linux中是冒号":"。

综上所述:

java -jar用来执行可执行jar包,其可执行的特性,由jar包中的清单属性Main-Class决定;

java -cp命令是纯粹的java命令,在指定的classpath中查找java类文件并执行,使用更灵活;