Java 与命令行

在日常写 Java 程序的工作中,运行,debug 等等操作,本质上都是在进行命令行操作。我们在 IDE 上点击运行,Java 程序就会运行,实际上 IDE 在背后帮我们进行了命令拼接。

我们可以在 IDEA 中编写一个简单的 Java 程序

1
2
3
4
5
6
7
8
9
10
11
package zzf;

/**
* @author zzf
* @date 2021/2/28/028 21:53
*/
public class Main {
public static void main(String[] args) {
System.out.println("Hello World");
}
}

在 zzf 包下面有个 Main.java 类,里面有个 main 方法输出了 “Hello World”。在 IDEA 中点击了运行按钮之后,控制台会有一串命令行

1
D:\java\jdk\bin\java.exe -javaagent:D:\software\Idea\ideaIU-2019.2.3.win\lib\idea_rt.jar=56956:D:\software\Idea\ideaIU-2019.2.3.win\bin -Dfile.encoding=UTF-8 -classpath D:\Java\jdk\jre\lib\charsets.jar;D:\Java\jdk\jre\lib\deploy.jar;D:\Java\jdk\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk\jre\lib\ext\cldrdata.jar;D:\Java\jdk\jre\lib\ext\dnsns.jar;D:\Java\jdk\jre\lib\ext\jaccess.jar;D:\Java\jdk\jre\lib\ext\jfxrt.jar;D:\Java\jdk\jre\lib\ext\localedata.jar;D:\Java\jdk\jre\lib\ext\nashorn.jar;D:\Java\jdk\jre\lib\ext\sunec.jar;D:\Java\jdk\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk\jre\lib\ext\sunmscapi.jar;D:\Java\jdk\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk\jre\lib\ext\zipfs.jar;D:\Java\jdk\jre\lib\javaws.jar;D:\Java\jdk\jre\lib\jce.jar;D:\Java\jdk\jre\lib\jfr.jar;D:\Java\jdk\jre\lib\jfxswt.jar;D:\Java\jdk\jre\lib\jsse.jar;D:\Java\jdk\jre\lib\management-agent.jar;D:\Java\jdk\jre\lib\plugin.jar;D:\Java\jdk\jre\lib\resources.jar;D:\Java\jdk\jre\lib\rt.jar;D:\idea-work\testDemo\out\production\testDemo zzf.Main

当我们把该命令复制到 CMD 窗口运行的时候,同样控制台会打印 “Hello World”

Java 执行过程

我们平时写的源代码(.java 文件),需要编译成字节码(.class 文件),然后再给到 jvm 去解释执行。jvm 只认识字节码,多个 class 文件可以打包成 jar 包来执行。

args 参数

我们写 Java 程序,main 方法里面都有一个 args 参数,实际上这个参数是可以从命令行获取的。编写以下程序获取打印 args 参数

1
2
3
4
5
public class Main {
public static void main(String []args){
System.out.println(java.util.Arrays.toString(args));
}
}

使用如下命令编辑和运行该程序

image.png
可以看到使用 java Main 运行时,打印为空字符串,而在后面添加 1 2 3 三个参数时,打印 [1,2,3] 。

java Main 1 2 3 表示,调用 java 这个可执行程序,然后把 Main 1 2 3 这四个参数传递个 java。java 把 Main 这个类名拿出来,并且运行这个类,后面的参数 1 2 3 当做这个类的参数,传递给这个类的 main 方法。

jvm 中的系统属性和环境变量

系统属性和环境变量是完全不同的东西,系统属性只在 jvm 中有效,不像环境变量可以继承属性。

我们可以在代码中使用 System.getenv() 来获取当前环境变量,使用 System.getProperty() 获取系统属性。我们可以编写如下代码(其中 java.version 是 jvm 自带的系统属性)

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
public static void main(String []args){
// 打印 args 参数
System.out.println("args: " +java.util.Arrays.toString(args));
// 打印名为 zzf 的环境变量
System.out.println("env: " +System.getenv("zzf"));
// 打印名为 zzf 的系统属性
System.out.println("System Property: " +System.getProperty("zzf"));
// 打印名为 java.version 的系统属性
System.out.println("Java version: " +System.getProperty("java.version"));
}
}

我们先使用 export zzf=helo 给当前环境添加环境变量 zzf,值为 hello,然后运行。

image.png
可以发现系统属性 zzf 并没有,打印为 null。而由于 jvm 存在系统属性 java.version,所以正确打印出版本号。要传入系统属性给 jvm 我们需要使用 -D 参数,如图所示。

image.png

java 代码中的包

假设有如下代码 zzf.java:

1
2
3
4
5
6
7
8
import org.apache.commons.lang3.StringUtils;
public class zzf{
public static void main (String[] args){
System.out.println(StringUtils.isBlank(args[0]));
System.out.println(StringUtils.isBlank(args[1]));
System.out.println(StringUtils.isBlank(args[2]));
}
}

该代码引用了第三方的包 org.apache.commons.lang3.StringUtils ,当我们使用 javac 编译的时候会报错,找不到这个包。因此,就需要指定这个包的目录,假设 commons-lang3-3.9.jar 文件和 zzf.java 文件在同一目录下,我们就可以使用 -classpath(简写 -cp),指定文件的位置。

1
javac -cp commons-lang3-3.9.jar zzf.java

这样就可以编译通过。但是在运行 java 程序的时候,需要同时指定引用的包的位置,还需要指定 zzf.class 文件位置

1
java -cp ./commons-lang3-3.9.jar:. zzf 1 2 3

该命令指定了第三方包的位置,以及 zzf.class 文件的位置。由于 zzf.class 文件是在当前目录,所以用 “.” 来表示。在 Linux 中多个目录用 “:” 隔开,Windows 使用 “;” 隔开。

总结

回到这个命令行

1
D:\java\jdk\bin\java.exe -javaagent:D:\software\Idea\ideaIU-2019.2.3.win\lib\idea_rt.jar=56956:D:\software\Idea\ideaIU-2019.2.3.win\bin -Dfile.encoding=UTF-8 -classpath D:\Java\jdk\jre\lib\charsets.jar;D:\Java\jdk\jre\lib\deploy.jar;D:\Java\jdk\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk\jre\lib\ext\cldrdata.jar;D:\Java\jdk\jre\lib\ext\dnsns.jar;D:\Java\jdk\jre\lib\ext\jaccess.jar;D:\Java\jdk\jre\lib\ext\jfxrt.jar;D:\Java\jdk\jre\lib\ext\localedata.jar;D:\Java\jdk\jre\lib\ext\nashorn.jar;D:\Java\jdk\jre\lib\ext\sunec.jar;D:\Java\jdk\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk\jre\lib\ext\sunmscapi.jar;D:\Java\jdk\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk\jre\lib\ext\zipfs.jar;D:\Java\jdk\jre\lib\javaws.jar;D:\Java\jdk\jre\lib\jce.jar;D:\Java\jdk\jre\lib\jfr.jar;D:\Java\jdk\jre\lib\jfxswt.jar;D:\Java\jdk\jre\lib\jsse.jar;D:\Java\jdk\jre\lib\management-agent.jar;D:\Java\jdk\jre\lib\plugin.jar;D:\Java\jdk\jre\lib\resources.jar;D:\Java\jdk\jre\lib\rt.jar;D:\idea-work\testDemo\out\production\testDemo zzf.Main

先不管 -javaagent ,从 -Dfile.encoding=UTF-8 给 jvm 设置一个系统属性 file.encoding=UTF-8,然后使用 -classpath 指定引用的包路径,要运行的文件的位置。最后只剩需要执行的文件名称 zzf.Main 。把上述这些都交给 D:\java\jdk\bin\java.exe 该可执行程序执行。


Java 与命令行
http://wszzf.top/2021/03/01/Java 与命令行/
作者
Greek
发布于
2021年3月1日
许可协议