命令行编译 Java 源文件

众所周知,Java 是一门编译型语言,需要编译成字节码才能在 JVM 上运行。常用的 IDE 如 Eclipse 等将编译、运行等步骤结合起来一起执行,只需要按下 Run 即可完成编译和运行的工作。但是实际上编译 java 程序的核心是 JDK。本文主要讲述了只安装 jdk 通过命令行来编译运行 Java 程序。

JDK 与 JRE

说到 JDK 和 JRE 的关系。可以简单认为 JDK 是用来编译 java 文件的,而 jre 是用来运行编译生成的 class 文件。JDK 中包含 JRE,在 JDK 的安装目录下有一个名为 jre 的目录,里面有两个文件夹 bin 和 lib,在这里可以认为 bin 里的就是 jvm,lib 中则是 jvm 工作所需要的类库,而 jvm 和 lib 和起来就称为 jre。

另外在 windows 下安装 jdk 是会有选择是否安装单独的 jre,如果选择安装,那么就会安装了两套 jre,一套包含在 jdk 安装目录中,另外一套则是独立安装的 jre。那么这两套 jre 有区别吗

答案是有的,因为 jdk 是作为开发使用的,而 jre 仅仅是作为运行 java 程序的环境。因此具备开发功能的 jdk 自己的 jre 下会同时有 client 性质的 jvm 和 server 性质的 jvm,而仅仅作为运行环境的 jre 下只需要 client 性质的 jvm.dll 就够了。

可根据需要编译的源文件的数目和位置将通过命令行编译运行 java 程序分成两大类。一类是只有单一的源文件,另外一种是有多个源文件。

单个源文件

单个原文件是最简单的了,编译命令为:
javac source.java
运行的命令为
java source
上面没有考虑单个源文件中引入的 jar 包,假如引入了不在 classpath 环境变量中的 jar 包时,需要在编译时加上 -classpath 参数。即命令为:
javac -classpath *.jar source.java

多个源文件

编译多个源文件是指其中一个源文件引用了另外一个源文件里面的类。这里可以根据源文件是否在同一个包进行以下分类。

源文件在同一个包

这时候只需要编译 “最顶层” 的类的源文件即可,比如说有以下三个类:

类 E 源文件如下

1
2
3
4
5
public class E{  
public E(){
System.out.println("this is E");
}
}

类 C 源文件如下

1
2
3
4
5
6
public  class C{  
public C(){
E e=new E();
System.out.println("this is C");
}
}

类 D 源文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class D{  
public static void main(String [] args){
C c=new C();
System.out.println("this is D");
}
}
```
现在这三个源文件在同一个包,也就是同一个文件夹下,此时**只需要编译类D的源文件即可**,执行时也只需要执行类D的class文件。即依次执行下面命令

```
javac D.java
java D
```
得到的结果如下:

```
this is E
this is C
this is D

源文件不在同一个包

这种情况下又可分为两种情况,详见下面例子

第一种情况:

类 B 的源文件如下:

1
2
3
4
5
6
7
8
package tcp;

public class B{
public B(){
System.out.println("this is B");
}

}

类 A 的源文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import tcp.*;

public class A{
public static void main(String [] args){
B b=new B();
System.out.println("this is A");
}
}
```
这时候需要建立一个名为`tcp`的目录,将类B的源文件放到tcp目录中,然后类A的源文件与tcp目录在同一个目录下,这时候只需要进入到类A所在目录下执行`javac A.java`即可生成`A.class`和`B.class`两个类文件,且`B.class`在tcp目录下生成。再执行命令`java A`便可得到以下结果:

```
this is B
this is A

第二种情况

在第一种情况下类 A 并没有在任何包中,那么假如类 A 也在一个包中该怎么编译运行呢?

在类 A 的源文件的开头添加多一行 pacakge udp; 即类 A 在包 udp 中,这时候通过命令行该怎么编译?

首先建立 tcpudp 两个文件夹且将他们放在同一目录,tcp 目录中放置 B.java,udp 目录中放置 A.java, 编译的方法有两种:

第一种:进入到 udp 目录,执行命令 javac -classpath .. A.java
第二种:不进入 tcp 或 udp,在 tcp 和 udp 所在的目录执行命令 javac udp\A.java

第一种方法的 - classpath 参数指出了 tcp 包所在目录,.. 表示上一层目录,这里采用了相对路径,也可采用绝对路径。

第二种方法利用了 jdk 编译时遇到 import 的包时会先在当前目录寻找的特性。

执行 A 程序的步骤则只有一种方法,就是在 tcp 和 udp 目录下执行命令
java udp.A