如何使用命令行编译和运行Java代码
由于被各种IDE和自动化构建工具“宠坏”了,最近我认识到我完全不知道如何使用命令行去运行Java代码。在玩了一个小时的猜谜游戏后,我花了5分钟,尝试去编译一小段代码,我认为也许直接花点时间去研究一下。
任务
我们有一个相当标准的Java工程,它包含三个顶层文件夹:
/bin-用来存放已编译好的.class
文件
/lib-用来存放第三方.jar
文件
/src-存放.java
源代码
我的任务就是要从Java工程根目录去编译和运行工程。我们将使用Windows操作系统作为例子(和在Unix系统上的唯一区别就是路径分隔符是”:
“而不是”;
“)。
编译Java代码
第一步是把文本文件.java
源代码编译成Java虚拟机字节码文件(.class
)。这一步使用一个叫javac的JDK工具来完成。
假设我们在应用的根目录下,从com.example
包下尝试把Application.java文件,以及把lib
文件夹中的lib1.jar
和lib2.jar
库编译到目标文件夹bin
下,编译命令应该是如下格式:
javac -d bin -sourcepath src -cp lib/lib1.jar;lib/lib2.jar src/com/example/Application.java
编译完后,/bin/com/example/Application.class
应该就会创建出来了。如何Application.java
使用了其他工程的类,那么他们全部会自动被编译并且放到相应的文件夹下。
运行Java代码
为了启动我们刚刚编译的.class
文件,需要另外一个叫java的JDK工具。
假设我们在应用的根目录下,为了能够启动com.example
包中的,使用了lib
文件夹下的lib1.jar
和lib2.jar
库的Application.class
文件,启动命令应该是如下
java -cp bin;lib/lib1.jar;lib/lib2.jar com.example.Application
我们在这里没有提供文件名,只有一个实际的类名,java会基于提供的classpath(缩写成cp)路径去搜索。
关于Classpath一些笔记
在Application.java
编译期间,编译器会碰到com.example.Util
类。编译器是如何在文件系统中找到它的呢?根据Java文件命令规则,Util类必须存放在Util.java文件的某处,但是从哪里开始去搜索这个路径呢?在这里就是classpath就要起到作用了,它设置了要搜索classes的起始目录。Classpath可以用3中不同的方式设置:
- 如果没有设置——那么classpath参数就会被忽略,环境变量中的CLASSPATH就会被使用到
- 如果环境变量CLASSPATH没找到,那么就是默认使用当前目录(”.”)
- 如果classpath作为命令行参数显示设置了,那么它就是覆盖所有其他的值。
事实就是当设置覆盖默认值(当前目录)时,classpath会造成不可预料的结果。
例如,如果我们没有使用任何第三方库,只有我们自己的com.example.Util
类,然后从src目录下编译Application.java
:
javac com/example/Application.java
这样做能成功,但是如果我们决定要添加一个第三方库到classpath时:
`javac -cp lib/lib1.jar com/example/Application.java`
这么做就会报错:
package com.example.Util does not exist
报错的原因是因为当我们设置-cp lib/lib1.jar
时,我们覆盖了classpath的默认值——当前目录。现在编译器将只会在jar文件里去搜搜所有的classes。为了修复这个问题,我们需要显示添加当前路径到classpath中:
javac -cp .;lib/lib1.jar com/example/Application.java