一篇文章让你秒懂Java运行基础
Javac编译
javac命令几个常用的选项
- -classpath 指定依赖的class文件搜索路径
- -sourcepath 指定依赖的源文件搜索路径
- -d 指定编译后的class存放目录,这个目录必须提前建好
- -extdirs 指定第三方依赖包,如jar、zip搜索目录
- -encoding 指定源文件编码 如UTF-8
下面以简单的java项目进行操作说明,所有命令操作都在项目根目录D:\kingfsen\workspace\java-demo
执行。
package引用
D:\kingfsen\workspace\java-demo>tree /F src/main/java
└─com
└─kingfsen
└─train
├─test
│ Test.java
│
├─test2
Test2.java
项目中有2个包,分别是test和test2,两个包下各有一个Java类,test2包下的Test2类引用了test包下的Test类。
public class Test2 {
public static void main(String[] args) {
Test t = new Test();
}
}
要编译Test2,如果不使用-classpath
、-sourcepath
,则需列出全部源代码文件进行编译。
javac -d target/class src/main/java/com/kingfsen/train/test2/*.java
src/main/java/com/kingfsen/train/test/*.java
编译Test类最简单,不依赖任何包。
javac -d target/class src/main/java/com/kingfsen/train/test/*.java
直接编译Test2类,javac直接编译报错,找不到Test类,可通过-sourcepath
指定源文件搜索路径。
javac -d target/class -sourcepath src/main/java
src/main/java/com/kingfsen/train/test2/*.java
也可以通过-classpath
指定依赖的class文件搜索路径,此时依赖的Test.class文件未生成,则将classpath当做sourcepath使用。
javac -d target/class -classpath src/main/java
src/main/java/com/kingfsen/train/test2/*.java
jar引用
有如下java项目
src
├─main
│ └─java
│ └─com
│ └─kingfsen
│ └─train
│ │ App.java
│ │
│ └─util
│ ListUtil.java
App类引用了util包下的ListUtil类,而ListUtil类的getEmptyList方法引用了google的guava包
public class App {
public static void main( String[] args ) {
List<String> emptyList = ListUtil.getEmptyList();
System.out.println("OK");
}
}
现在编译App.java、ListUtil.java两个源代码文件
javac src/main/java/com/kingfsen/train/*.java src/main/java/com/kingfsen/train/util/*.java
src\main\java\com\kingfsen\train\util\ListUtil.java:3: 错误: 程序包com.google.common.collect不存在
import com.google.common.collect.Lists;
^
src\main\java\com\kingfsen\train\util\ListUtil.java:14: 错误: 找不到符号
return Lists.newArrayList();
编译时发生错误,找不到ListUtil中依赖的guava的jar包,通过-classpath
指定依赖包文件路径则可编译成功。
javac -d target/class
-classpath "D:\maven\respoistory\com\google\guava\guava\18.0\guava-18.0.jar"
src/main/java/com/kingfsen/train/util/*.java
如果源代码依赖了多个jar包,jar包路径以;拼接
-classpath "D:\maven\respoistory\junit\junit\3.8.1\junit-3.8.1.jar;D:\maven\respoistory\com\google\guava\guava\18.0\guava-18.0.jar"
依赖的三方jar包也可以通过-extdirs指定,它是个目录集合
javac -d target/class -extdirs "D:\maven\respoistory\com\google\guava\guava\18.0" src/main/java/com/kingfsen/train/util/*.java
此时编译App.java,还需把依赖的util包下的List.class搜索路径src/main/java添加到classpath中
javac -d target/class -classpath "src/main/java;D:\maven\respoistory\junit\junit\3.8.1\junit-3.8.1.jar;D:\maven\respoistory\com\google\guava\guava\18.0\guava-18.0.jar" src/main/java/com/kingfsen/train/App.java
通常一般通过-extdirs来指定一些扩展依赖jar、zip搜索路径,classpath来指定源文件或者class文件搜索路径, 一次要编译源文件太多,可以全部放在一个源文件清单中,如sourcefile.txt。
src/main/java/com/kingfsen/train/App.java
src/main/java/com/kingfsen/train/util/ListUtil.java
javac -d target/class -classpath src/main/java -extdirs "D:\maven\respoistory\junit\junit\3.8.1\junit-3.8.1.jar;D:\maven\respoistory\com\google\guava\guava\18.0" @sourcefile.txt
Java运行
在Java中,有两种常用的运行方式,直接运行主体类main方法,或者java -jar xxx.jar。
MainClass
通过-classpath指定所有的class文件搜索路径,包括javac生成的字节码目录target/class。
java -classpath "D:\maven\respoistory\junit\junit\3.8.1\junit-3.8.1.jar;D:\maven\respoistory\com\google\guava\guava\18.0\guava-18.0.jar;target/class" com.kingfsen.train.App
Jar
打普通jar包
jar cf demo.jar target/class/*
查看jar包中文件清单
jar tfv demo.jar
解压jar包
jar xf demo.jar
0 Mon Jul 03 11:42:30 CST 2023 META-INF/
69 Mon Jul 03 11:42:30 CST 2023 META-INF/MANIFEST.MF
0 Mon Jul 03 10:24:54 CST 2023 target/class/com/
0 Mon Jul 03 10:24:54 CST 2023 target/class/com/kingfsen/
0 Mon Jul 03 10:41:48 CST 2023 target/class/com/kingfsen/train/
507 Mon Jul 03 11:00:52 CST 2023 target/class/com/kingfsen/train/App.class
0 Mon Jul 03 10:24:54 CST 2023 target/class/com/kingfsen/train/test/
203 Mon Jul 03 11:00:52 CST 2023 target/class/com/kingfsen/train/test/Test.class
0 Mon Jul 03 10:26:26 CST 2023 target/class/com/kingfsen/train/test2/
325 Mon Jul 03 11:00:52 CST 2023 target/class/com/kingfsen/train/test2/Test2.class
0 Mon Jul 03 10:39:34 CST 2023 target/class/com/kingfsen/train/util/
438 Mon Jul 03 11:00:52 CST 2023 target/class/com/kingfsen/train/util/ListUtil.class
打Java可执行包时,需要提前准备一个Manifest内容的txt文件
Manifest-Version: 1.0
Created-By: kingfsen
Main-Class: com.kingfsen.train.App
通过jar cfm
打可执行包
cd target/class
jar cfm demo.jar D:/kingfsen/workspace/java-demo/manifest.txt .
注意可执行jar中的目录必须是包的起始子目录com,而不是target/class,此时可通过java的扩展加载器加载依赖的第三方jar,使用-Djava.ext.dirs
java -Djava.ext.dirs="$JAVA_HOME/jre/lib/ext;D:\maven\respoistory\junit\junit\3.8.1;D:\maven\respoistory\com\google\guava\guava\18.0" -jar demo.jar
也可以通过根加载器加载第三方jar,使用-Xbootclasspath/a
java -Xbootclasspath/a:"D:\maven\respoistory\junit\junit\3.8.1\junit-3.8.1.jar;D:\maven\respoistory\com\google\guava\guava\18.0\guava-18.0.jar" -jar demo.jar
java -jar xxx.jar
命令运行时,classpath
被自动设置为xxx.jar
,此时命令行使用-classpath
无效,如需通过应用加载器加载第三方jar,需要在manifest中将依赖包添加到classpath中。
MANIFEST.MF中的Class-Path
只能使用\
,不能出现任何反斜杠,也不能出现绝对路径。
执行 jar -jar demo.jar
是,只能以demo.jar
路径起始定义Class-Path
, 多个jar以空格隔开,通常新建一个目录lib,将jar都copy到lib目录中。
manifest文件
Manifest-Version: 1.0
Created-By: kingfsen
Class-Path: lib/mysql-connector-j-8.0.31.jar lib/guava-18.0.jar xx.jar
Main-Class: com.kingfsen.train.App
打包运行
jar cfm demo.jar D:/kingfsen/workspace/java-demo/manifest.txt .
java -jar demo.jar
除了使用java提供的二进制命令打包,还可以直接使用Java中API进行打包,可参阅JarOutputStream源代码。
java打包命令参考:https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html