Java编程语言、J2SE、J2EE等教程在入门阶段基本均未使用IDE,编译源文件时基本都是采用命令行编译的方式。这就造成像我一样的Java初学者,在一步一步按照教程上操作之后仍然无法编译成功的情况。后果就是有些人可能就此放弃学习Java,或者只是简单百度一下,无果后要么放弃要么改用其他教程。而我相信一个真正爱好编程、爱好钻研的人都不会对遇见的问题不了了之、视而不见。
无论如何,作为一个Java Web初学者的我,会把从今天开始学习Java Web的一点点心得和经验分享给大家,希望能够有所帮助。闲言少叙,让我们进入今天的主题——Java源文件编译问题汇总。
假设我的工作目录为一个叫做test的文件夹,后续文章除非特殊说明,否则的话工作均是从test文件夹下展开。首先就让我们先从最简单的情况入手。
我有一个java源文件叫做“Test.java”,我把它存放在C:\test\目录下,它的功能只是向控制台输出“Welcome!”,源代码如下所示:
//Test.java public class Test { public static void main(String[] args) { System.out.printf("Welcome!"); } }
当然,首先我要先使用cd C:\test命令设置当前的工作目录。之后,相信每个Java-er都会使用
javac Test.java
命令来编译,编译成功!编译后的目录结构如下图所示。
在继续分享后续内容之前,我需要简单介绍以下javac的-d参数。一言以蔽之——-d参数用于
将编译产生的源文件存入反应包名的指定路径中
。仍旧以Test.java文件为例说明,修改后的源代码如下所示:
//Test.java package com.example.web; public class Test { public static void main(String[] args) { System.out.printf("Welcome!"); } }
通常情况下,我们仍旧会使用
javac Test
.
java
命令编译,这个命令默认会把编译的.class文件存放在和源文件相同的目录下。假如此时我使用-d参数来编译这个加入了包的源文件会发生什么呢?我先用
javac
-
d
.
Test
.
java
(其中的.表示将编译产生的.class文件存放在当前目录下)来编译,我们发现会在test目录下产生一个叫做com\example\web的子目录。
按照大多数Java Web教程或者其他的Java类书籍中提到的,我们通常会将编译产生的.class文件存放在项目根目录下的WEB-INF\classes目录下。所以,我在test目录下新建一个叫做classes的文件夹,然后用
javac
-
d WEB
-
INF\classes Test
.
java
编译,编译产生的class文件会存放在WEB-INF\classes目录下的com\exmaple\web目录下,如下图所示:
目前为止,我们知道-d参数可以任意指定编译产生的.class文件的存放路径,甚至可以指定为月球(HaHa...说好的只是简单说一下-d参数的,还是说了这么多废话-_-!!!)。
接下来让我们正式请出今天的主角:依赖于其他类的源文件如何编译,我会把“其他的类”分为两部分来讲解:
1. “其他的类”为自己定义的类;
2. “其他的类”为Servlet或JSP等特殊的类;
让我们先从“其他的类”为自己定义的类开始讲解,假设我现在有一个叫做Rectangle的矩形类,他有两个私有成员分别表示矩形的长度和宽度,还有一个公有成员函数用于返回矩形的面积。另外我还有一个叫做Test的类,Test中的main函数实例化了Rectangle并且调用getArea()函数得到矩形的面积并打印到控制台。以下是这两个类的源代码:
//Rectangle.java public class Rectangle { private int width; private int height; Rectangle(int width, int height) { this.width = width; this.height = height; } public int getArea() { return (this.width * this.height); } } //Test.java public class Test { public static void main(String[] args) { Rectangle rect = new Rectangle(5, 10); System.out.println(rect.getArea()); } }
假如这两个类在同一个目录下,我们只需使用
javac Test
.
java
来编译Test.java即可,编译器会自动识别Rectangle类并编译,以下是编译后的目录结构:
让我们试着把情况变得复杂一些:我们在test下新建一个名为others的目录,并把Rectangle.java源文件移动到others目录下,现在的目录结构如下所示:
现在我们继续使用
javac Test
.
java
编译会得到如下图所示的错误,错误信息提示在编译Test.java文件的时候找不到Rectangle类,或者编译器不知道Rectangle符号是什么玩意儿。
这是因为编译器在当前目录下找不到Rectangle.java。现在该是-sourcepath参数闪亮的时候了,这个参数可以自定义被依赖的类的搜索路径。所以现在我们可以使用
javac
-
sourcepath others Test
.
java
命令来编译,编译后的目录结构如下所示:
让我们继续把情况变得复杂一些,废话少说直接上修改后的目录结构以及源代码:
//Rectangle.java package bar; public class Rectangle { private int width; private int height; public Rectangle(int width, int height) { this.width = width; this.height = height; } public int getArea() { return (this.width * this.height); } } //Test.java package foo; import bar.*; public class Test { public static void main(String[] args) { Rectangle rect = new Rectangle(5, 10); System.out.println(rect.getArea()); } }
通过-sourcepath参数的讲解后我们不难得出可以通过
javac
-
sourcepath src src\foo\Test
.
java
来编译。以下是编译后的目录结构:
但是,当我们在做Java Web项目或者其他我不了解的项目的时候,我们都会在项目的目录下建一个classes文件夹专门用于存放编译产生的.class文件,示例的目录结构如下左图所示,通过命令
javac
-
d classes
-
sourcepath src src\foo\Test
.
java
编译后的目录结构如下右图(-_-!!!)所示:
让我们来看看最后一种我在学习孙鑫的Java Web教程中遇到的情况(Test和Rectangle的源代码未作修改,此种情况困扰了我这个Java Web菜鸟很长时间)。目录结构如下所示:
这种情况下无论我们使用
javac
-
d classes src\Test
.
java
还是
javac
-
d classes
-
sourcepath src src\Test
.
java
都无法编译成功。目前为止我的解决办法是需要根据Test.java和Rectangle.java中的导包的情况手动创建目录结构如下图如所示,然后通过
javac
-
d classes
-
sourcepath src src\foo\Test
.
java
编译即可。
(在这里,我不得不吐槽以下各位Java前辈们在编书时的态度。一万只草泥马在屏幕上奔腾而过~!@#¥%……&*)
最后,这次真的是最后一部分。让我们来讨论一下“其他的类”为Servlet或JSP等特殊的类的情况。这种情况下若要成功编译有两种方式可以选择,第一:设置classpath环境变量;第二:编译的时候手动设置-classpath参数。由于总有那么一些人在设置环境变量的时候出现问题,所以在这里我只介绍一下万能的第二种方法。
我在这里举一个Servet源文件编译的例子(不懂Java Web或者不懂Servlet的朋友们不要太在意,等下我会提示大家重点需要注意的地方)。具体的目录结构如下所示和源代码如下所示:
//BeerSelect.java package com.example.web; import com.example.model.*; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class BeerSelect extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //response.setContentType("text/html"); //PrintWriter out = response.getWriter(); //out.println("Beer Selection Advice<br>"); String c = request.getParameter("color"); BeerExpert be = new BeerExpert(); List result = be.getBrands(c); request.setAttribute("styles", result); RequestDispatcher view = request.getRequestDispatcher("result.jsp"); view.forward(request, response); /* Iterator it = result.iterator(); while(it.hasNext()) { out.println("<br>try: " + it.next()); } */ } } //BeerExpert.java package com.example.model; import java.util.*; public class BeerExpert { public List getBrands(String color) { List brands = new ArrayList(); if (color.equals("amber")) { brands.add("Jack Amber"); brands.add("Red Moose"); } else { brands.add("Jail Pale Ale"); brands.add("Gout Stout"); } return(brands); } }
很明显BeerSelect类继承自HttpServlet类,BeerSelect引用了另外一个包内的BeerExpert类。我们的目标是成功编译BeerSelect.java。
但是,由于编译HttpServlet这个类所需要的jar文件路径是“C:\tomcat-9.0\lib\servlet-api.jar”,若要成功编译BeerSelect.java需要使用-classpath参数手动指定这个api所在的路径。
假设我们的当前目录是BeerV1,编译BeerSelect.java的命令是:
javac
-
classpath
C:
\tomcat
-9.0
\lib\servlet
-
api
.
jar
-
d classes
-
sourcepath src src\com\example\web\BeerSelect
.
java
,编译后的而目录结构如下所示:
至此,我在学习Java以及Java Web时遇到的关于源文件编译问题已经全部分享完毕,希望多少能够帮助大家。有任何疑问可以通过评论或通过文章最后列出的联系方式联系我,希望大家不吝赐教。
个人邮箱:
xueyublue@gmail.com
工作邮箱:
xuey@daifuku.com.sg
丘丘号码:905375641