我们都知道Java需要编译成字节码才可以供Java虚拟机加载执行,实现我们代码中的功能,现在集成开发环境都帮我们做了编译的工作,我们只需要执行run,编译器便把我们编写的Java源码文件编译,执行,但如果没有集成开发环境,我们该如何对编写的项目进行编译呢。
一、简单编译
首先从一个简单的demo引入,我们编写一个HelloWorld.java如下
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello word");
}
}
在初学java的时候都会学习到 ,使用 javac HelloWorld.java 编译这个文件
javac HelloWorld.java
在同目录下会生成 HelloWorld.class 文件,这就是编译出的java字节码文件,在同目录下执行
java HelloWorld
即可输出结果
Hello word
这是最简单的单个类编译
二、带包编译
但多数情况我们搭建项目并不只是只编写一个文件,我们还需要编写多个包,每个包下面有各自的文件,要对带包的项目进行编译我们如何操作呢?
我们新建一个项目,在源代码根目录java 下创建三个包,bean,main,util。
java
├── bean
│ └── Student.java
├── main
│ └── Main.java
└── util
└── DBUtils.java
Student.java
package bean;
public class Student {
String name;
}
DBUtils.java
package util;
import java.sql.Connection;
public class DBUtils {
public static Connection getConn(){
return null;
}
}
Main.java
package main;
import bean.Student;
import util.DBUtils;
import java.sql.Connection;
public class Main {
public static void main(String[] args) {
Student stu = new Student();
Connection conn = DBUtils.getConn();
System.out.println("ok");
}
}
Main.java 中有我们的主方法入口,其实我们引入Student和 DBUtils类什么都没做,最后输出的ok,目的是为了编译Main的时候能引入其他的类。
这里我们到java/main 目录下,尝试编译Main.java,执行 javac Main.java ,却和我们在没有包的时候不一样了,没有编译成功,提示错误
Main.java:14: 错误: 找不到符号
Connection conn = DBUtils.getConn();
^
符号: 变量 DBUtils
位置: 类 Main
5 个错误
因为我们再 main的文件夹下,Main.java 中引入了包 utils.DBUtils , 但javac编译程序首先会从编译命令执行的目录,也就是java/main去查找是否存在util/DButils类,结果发现不存在,所以报错,所以我们必须在这些包的根目录下去执行编译操作,这样各个包之间才能互相找到。
正确的姿势是到项目的根目录,也就是java目录下 ,执行
javac main/Main.java
编译成功,可以看到我们的每个类的目录下出现了同名的class后缀文件
java
├── bean
│ ├── Student.class
│ └── Student.java
├── main
│ ├── Main.class
│ └── Main.java
└── util
├── DBUtils.class
└── DBUtils.java
接着执行
java main.Main
运行成功。
之所以要加main,是因为java命令都是需要输入类的 全路径名 才能运行,即使我跳到main目录下执行 java Main也不行,所以在执行的时候一定要主要加上类的全路径名。
三、带包编译
熟悉上面两个步骤,自己编写简单的java代码是没有问题了,但如果我们想要引入第三方的库(例如需要转JSON,或者使用httpclient库等),使我们的程序更强大,那应该怎么引入第三方库进行编译呢?
我们这里重新利用一下 二 中的项目,将之前已经编译出的字节码文件删除。
在原有的 Main.java 中添加一个使用 阿里巴巴fastjson库 创建json对象的代码,更改后如下
package main;
import bean.Student;
import com.alibaba.fastjson.JSONObject;
import util.DBUtils;
import java.sql.Connection;
public class Main {
public static void main(String[] args) {
Student stu = new Student();
Connection conn = DBUtils.getConn();
JSONObject jsonObject = new JSONObject();
jsonObject.put("errmsg","ok");
System.out.println(jsonObject.toString());
}
}
我们执行编译前目录如下
java/
├── bean
│ └── Student.java
├── main
│ └── Main.java
└── util
进入到java目录下执行 javac main/Main.java ,编译报错
main/Main.java:16: 错误: 找不到符号
JSONObject jsonObject = new JSONObject();
^
符号: 类 JSONObject
位置: 类 Main
3 个错误
提示找不到JSONObject 类,的确,虽然我们使用了 fastjson库,但是编译的时候总得告诉编译器,怎么去找到这个类吧,
于是我们可以使用 javac 命令的 -classpath 参数 来进行编译,我们先把fastjson的jar包准备好,放在根路径下的lib目录下,如下
java/
├── bean
│ └── Student.java
├── lib
│ └── fastjson-1.1.29.jar
├── main
│ └── Main.java
└── util
└── DBUtils.java
在根目录执行
javac -classpath .:lib/fastjson-1.1.29.jar main/Main.java
编译成功,这里的classpath参数是为了让编译器去找编译所需依赖的类的路径,默认其实就是 . ,即当前路径,比如main/Main.java 依赖了 bean.Student类,实际上编译器会先去当前路径下的 bean查找Student类是否有Student.class文件,如果有,就使用Student.class 文件,如果没有那再看有没有Student.java 文件,如果有,那就编译成Student.class 文件使用。如果Student.java 和 Student.class 文件都没有,那抱歉。编译器说:啥都没有,这活儿我干不了。于是就报错了。
编译成功后执行也是类似,得加上-classpath 来执行
java -classpath .:lib/fastjson-1.1.29.jar main/Main
运行成功,输出
{"errmsg":"ok"}
这样我们一个依赖第三方库的项目便使用java编译命令编译成功了
四、结束语
其实我们通常写一些大型的项目都是用集成开发环境,再使用一些封装后的编译工具(Maven等)进行编译,我们只需要添加依赖,设定编译目标,程序便打包好出现在我们的眼前,但使用工具的前提是我们得知道工具到底为我们做了哪些事情,这样在工具不能正常工作的时候,我们才能快速定位到问题所在。