编译Java项目

一直用Meavn编译打包应用。期间也断断续续了解过一些编译的命令,但是不是很系统尤其是对classpath概念的模糊,这一次写一篇文章记录一下自己的成果。

参考的博客:

http://www.cnblogs.com/haolujun/archive/2013/03/02/2939698.html

javac命令(编译)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
用法: javac <options> <source files>
其中, 可能的选项包括:
-g 生成所有调试信息
-g:none 不生成任何调试信息
-g:{lines,vars,source} 只生成某些调试信息
-nowarn 不生成任何警告
-verbose 输出有关编译器正在执行的操作的消息
-deprecation 输出使用已过时的 API 的源位置
-classpath <路径> 指定查找用户类文件和注释处理程序的位置
-cp <路径> 指定查找用户类文件和注释处理程序的位置
-sourcepath <路径> 指定查找输入源文件的位置
-bootclasspath <路径> 覆盖引导类文件的位置
-extdirs <目录> 覆盖所安装扩展的位置
-endorseddirs <目录> 覆盖签名的标准路径的位置
-proc:{none,only} 控制是否执行注释处理和/或编译。
-processor <class1>[,<class2>,<class3>...] 要运行的注释处理程序的名称; 绕过默认的搜索进程
-processorpath <路径> 指定查找注释处理程序的位置
-parameters 生成元数据以用于方法参数的反射
-d <目录> 指定放置生成的类文件的位置
-s <目录> 指定放置生成的源文件的位置
-h <目录> 指定放置生成的本机标头文件的位置
-implicit:{none,class} 指定是否为隐式引用文件生成类文件
-encoding <编码> 指定源文件使用的字符编码
-source <发行版> 提供与指定发行版的源兼容性
-target <发行版> 生成特定 VM 版本的类文件
-profile <配置文件> 请确保使用的 API 在指定的配置文件中可用
-version 版本信息
-help 输出标准选项的提要
-A关键字[=值] 传递给注释处理程序的选项
-X 输出非标准选项的提要
-J<标记> 直接将 <标记> 传递给运行时系统
-Werror 出现警告时终止编译
@<文件名> 从文件读取选项和文件名

java命令(运行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
用法: java [-options] class [args...]
(执行类)
或 java [-options] -jar jarfile [args...]
(执行 jar 文件)
其中选项包括:
-d32 使用 32 位数据模型 (如果可用)
-d64 使用 64 位数据模型 (如果可用)
-server 选择 "server" VM
默认 VM 是 server,
因为您是在服务器类计算机上运行。

-cp <目录和 zip/jar 文件的类搜索路径>
-classpath <目录和 zip/jar 文件的类搜索路径>
用 : 分隔的目录, JAR 档案
和 ZIP 档案列表, 用于搜索类文件。
-D<名称>=<值>
设置系统属性
-verbose:[class|gc|jni]
启用详细输出
-version 输出产品版本并退出
-version:<值>
需要指定的版本才能运行
-showversion 输出产品版本并继续
-jre-restrict-search | -no-jre-restrict-search
在版本搜索中包括/排除用户专用 JRE
-? -help 输出此帮助消息
-X 输出非标准选项的帮助
-ea[:<packagename>...|:<classname>]
-enableassertions[:<packagename>...|:<classname>]
按指定的粒度启用断言
-da[:<packagename>...|:<classname>]
-disableassertions[:<packagename>...|:<classname>]
禁用具有指定粒度的断言
-esa | -enablesystemassertions
启用系统断言
-dsa | -disablesystemassertions
禁用系统断言
-agentlib:<libname>[=<选项>]
加载本机代理库 <libname>, 例如 -agentlib:hprof
另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<选项>]
按完整路径名加载本机代理库
-javaagent:<jarpath>[=<选项>]
加载 Java 编程语言代理, 请参阅 java.lang.instrument
-splash:<imagepath>
使用指定的图像显示启动屏幕

jar命令(打包)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
选项:
-c 创建新档案
-t 列出档案目录
-x 从档案中提取指定的 (或所有) 文件
-u 更新现有档案
-v 在标准输出中生成详细输出
-f 指定档案文件名
-m 包含指定清单文件中的清单信息
-n 创建新档案后执行 Pack200 规范化
-e 为捆绑到可执行 jar 文件的独立应用程序
指定应用程序入口点
-0 仅存储; 不使用任何 ZIP 压缩
-P 保留文件名中的前导 '/' (绝对路径) 和 ".." (父目录) 组件
-M 不创建条目的清单文件
-i 为指定的 jar 文件生成索引信息
-C 更改为指定的目录并包含以下文件

编译最简单的应用

文件目录

1
test02--|---src---|---A.java--|

代码

1
2
3
4
5
6
7
8
9

public class A{
public A(){
System.out.println("I am A!");
}
public static void main(String[] args){
new A();
}
}

运行命令

1
2
3
cd java/test01/src
javac A.java
java A

输出结果

1
I am A!

classpath

(1)要想成功编译java文件,需要有classpath和包名(package)的共同配合。

类发现规则:class文件所在目录 = classpath + ‘\’ + 包名(包名中的’.’全变成’\’)

这个规则大家一定要记住,保证万事OK!Java就是靠这个规则来寻找需要的class文件的。

(2)何时需要使用-classpath:当你要编译或执行的类引用了其它的类,但被引用类的.class文件不在当前目录下时,就需要通过-classpath来引入类
(3)何时需要指定路径:当你要编译的类所在的目录和你执行javac命令的目录不是同一个目录时,就需要指定源文件的路径(CLASSPATH是用来指定.class路径的,不是用来指定.java文件的路径的)

引入package

文件目录

1
2
test03--|---src---|---com---|-baobing-|---A.java--|
|--B.java-|

代码

1
2
3
4
5
6
7
package src.com.baobing;
public class A{
public A(){
System.out.println("I am A!");
}

}
1
2
3
4
5
6
7
8
9
10
11
12

package src;
import src.com.baobing.*;
public class B{
public B(){
A a = new A();
System.out.println("I am B!");
}
public static void main(String[] args){
new B();
}
}

运行命令

1
2
3
cd ~/java/test02
javac -cp ~/java/test02 src/B.java
java src.B

输出结果

1
2
I am A!
I am B!

需要注意的是包名一定更要和文件目录一一对应。 否则会报错。
编译时给出正确的classpath和正确的包名,javac程序即可自动查找编译B.java依赖的A.java文件。

打JAR包

文件路径以及代码都与《引入package》环节的一致,就不赘述了。

运行命令

1
2
3
4
cd java/test03
javac src/*.java
jar cvf test03.jar src
java -cp test03.jar src.B

输出结果

1
2
I am A!
I am B!

引用jar包

1
2
---test04--|---src---|---C.java--|
|---lib---|test03.jar-|

代码

1
2
3
4
5
6
7
8
9
10
package src;
import src.*;
import src.com.baobing.*;
public class C{
public static void main(String[] args){
new A();
System.out.println("------------------");
new B();
}
}

运行命令

1
2
3
4
5
cd java/test04
javac -cp ./lib/test03.jar src/C.java
# 因为是macos所以用:隔开,必须加上./,否则会报错。揣测是因为使用-cp
# 就不能使用默认的classpath
java -cp ./lib/test03.jar:./ src.C

运行结果

1
2
3
4
I am A!
------------------
I am A!
I am B!

可执行jar包

文件目录

1
2
3
test03--|---src-----|---com---|-baobing-|---A.java--|
|--B.java-|
|MANIFEST.MF|

代码

A.java和B.java的代码与《引入package》环节的一致,不赘述。

注意事项:Main-Class一定要是第一行,不知道原因

1
2
3
Main-Class: src.B
Manifest-Version: 1.0
Created-By: 1.8.0_51 (Oracle Corporation)

运行命令

1
2
3
cd java/test05
jar cvfm test.jar MANIFEST.MF src/B.class src/com/baobing/A.class
java -jar test.jar

输出

1
2
I am A!
I am B!