- 浏览: 5398 次
- 性别:
- 来自: 北京
最新评论
很多书籍和网络教程关于Java编程环境搭建的内容,一般都言简意赅,赘述如下:
1、安装JDK and JRE,然后设置环境变量
2、新建"JAVA_HOME”变量,设置为JDK的安装路径
3、新建"CLASSPATH”变量,设置为"%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\dt.jar;."
4、修改"Path”变量,补充"%JAVA_HOME%\bin”
5、编写一段程序,然后javac&java,Hello World
确实,搞定"Hello World”是一件挺简单的事,如果使用某些IDE甚至连上述步骤都可以略掉,javac和java他俩点了回名就被扔到了墙角。当然这无可厚非,强大的IDE让我们的编码工作变得单纯了许多。然而,他们果真不值一提么?
先想想下面这个小场景,如果刚刚读完场景你就完全明白怎么回事,请略过本文,很抱歉浪费了你看上文的时间;如果你确实还有些含糊,那不妨花上几分钟一起研究下。
场景描述:com.idearye.main.MyMain.java和com.idearye.friend.MyFriend.java两个文件,MyMain类import了MyFriend类,并在main方法中创建一个MyFriend对象,异常简单的场景。如果使用IDE,工程中创建两个包两个文件,然后build完事。但,如果不使用IDE,你是否还能正确的应用javac和java编译及运行这个程序?如果稍微再搞复杂一些,MyFriend类又import了另一个类com.idearye.enemy.MyEnemy,三个文件分处在三个包中,对你是否依然简单?
MyMain.java和MyFriend.java源代码如下:
package com.idearye.main; import com.idearye.friend.*; public class MyMain{ public static void main(String[] args){ MyFriend myFriend = new MyFriend(); } } package com.idearye.friend; public class MyFriend{ public MyFriend(){ } }
package是Java引入的非常漂亮的组织结构理念,合理的打包能让应用程序各模块得到有序的维护,因此在有点规模有点心思的程序中,基本不会出现所有文件都在同一目录的情况。
我的尝试:
第一步,直接在main目录中编译的后果是:
>> javac MyMain.java >> MyMain.java:3: package com.idearye.friend does not exist >> import com.idearye.friend.*; >> ^ >> MyMain.java:7: cannot find symbol >> symbol : class MyFriend >> location: class com.idearye.main.MyMain >> MyFriend myFriend = new MyFriend(); >> ^ >> MyMain.java:7: cannot find symbol >> symbol : class MyFriend >> location: class com.idearye.main.MyMain >> MyFriend myFriend = new MyFriend(); ^ >> 3 errors
第二步,提示MyMain找不到com.idearye.friend.MyFriend类,如果我预先编译一下MyFriend类呢?并将MyFriend.class文件拷贝到main目录中,这下你总该能找到了吧?
>> cd friend >> javac MyFriend.java >> 这步没有任何错误,将生成的class文件拷贝到main目录中 >> javac MyMain.java >> MyMain.java:3: package com.idearye.friend does not exist >> import com.idearye.friend.*; >> ^ >> MyMain.java:7: cannot find symbol >> symbol : class MyFriend >> location: class com.idearye.main.MyMain >> MyFriend myFriend = new MyFriend(); >> ^ >> MyMain.java:7: cannot find symbol >> symbol : class MyFriend >> location: class com.idearye.main.MyMain >> MyFriend myFriend = new MyFriend(); ^ >> 3 errors
嘿,当前路径下明明有class文件,而且系统的CLASSPATH环境变量中也有"."代表当前路径啊,编译器怎么还提示这个错误呢?
第三步,先不说原因,我们这样试试先,仍然回到main目录中
>> cd main >> javac -sourcepath "D:\00_code\99_OTHER\Java\src" -classpath "D:\00_code\99_OTHER\Java\classes" -d "D:\00_code\99_OTHER\Java\classes" MyMain.java >> 没有任何提示,编译成功,回到包的顶层,即"D:\00_code\99_OTHER\Java\",查看目录树 >> tree /f >> ├─classes >> │ └─com >> │ └─idearye >> │ ├─friend >> │ │ MyFriend.class >> │ └─main >> │ MyMain.class >> └─src >> └─com >> └─idearye >> ├─friend >> │ MyFriend.java >> └─main >> MyMain.java
或者,我们回到D盘根目录,玩一个跨度更大的!
>> javac -sourcepath "D:\00_code\99_OTHER\Java\src" -classpath "D:\00_code\99_OTHER\Java\classes" -d "D:\00_code\99_OTHER\Java\classes" D:\00_code\99_OTHER\Java\src\com\idearye\main\MyMain.java >> 没有任何提示,编译成功,回到包的顶层,即"D:\00_code\99_OTHER\Java\",查看目录树 >> tree /f >> ├─classes >> │ └─com >> │ └─idearye >> │ ├─friend >> │ │ MyFriend.class >> │ └─main >> │ MyMain.class >> └─src >> └─com >> └─idearye >> ├─friend >> │ MyFriend.java >> └─main >> MyMain.java
恩,可以正确编译的程序和编译错误的程序,在于为javac指定了3个参数,"-sourcepath”、"-classpath”和"-d"。这三个参数对于编译器的意味着什么呢?
我们还是先说一下为何第一步与第二步会出现失败。一个类需要指明所属的包的,包路径与类名共同组成了该类的完整名称,即某某书上说的专业术语“完全限定类名”云云。编译器要找到一个类,需要这个“完全限定类名”。我们打一个比方,好比警察要找你,光知道你的名字是没用的,警察需要知道你是哪个国家、哪个省、哪个城市、哪个片区、哪个小区、哪个门牌号,当然,作为警察,他可以穷举这个世界所有叫你这个名字的人,然后一个个的排查,好比《盗墓笔记》中张大佛爷把全国叫张起灵的都揪出来,但,这需要大量资源,警察不会这么二,于是蛋生了蛋疼的户口本;编译器也不会这么二,于是蛋生了下一段:
MyMain类中引用了MyFriend类,而MyFriend类位于com.idearye.friend包中,编译器会从"classpath”参数指明的目录中寻找"MyFriend.class"文件,然后到"sourcepath"参数指明的目录中寻找"MyFriend.java"文件。如果同时找到这两个东西,则会判断它们蛋生的时间。如果MyFriend.java新于MyFriend.class,则会重新编译MyFriend.java,否则会直接使用MyFriend.class。如果只找到了MyFriend.java,就启动编译,如果只找到了MyFriend.class,就直接使用。如果都找到,就会抛出前两种场景中著名的“Cann't Find Symbol”的错误。
而"-d"参数指明了生成的class文件保存的根目录,如果类的源文件声明了所属包,则会在该目录中生成包对应的目录树结构,这个参数很简单。我们可以回想一下诸如Eclips创建工程时,你可以指明output或者bin目录,其实IDE就是根据这个参数来放置生成的class文件,同时也会自动从这个目录中开始寻找所需要的类。
MyMain类中引用了MyFriend类,而MyFriend类位于com.idearye.friend包中,编译器会从"classpath”参数指明的目录中寻找"MyFriend.class"文件,然后到"sourcepath"参数指明的目录中寻找"MyFriend.java"文件。如果同时找到这两个东西,则会判断它们蛋生的时间。如果MyFriend.java新于MyFriend.class,则会重新编译MyFriend.java,否则会直接使用MyFriend.class。如果只找到了MyFriend.java,就启动编译,如果只找到了MyFriend.class,就直接使用。如果都找到,就会抛出前两种场景中著名的“Cann't Find Symbol”的错误。
而"-d"参数指明了生成的class文件保存的根目录,如果类的源文件声明了所属包,则会在该目录中生成包对应的目录树结构,这个参数很简单。我们可以回想一下诸如Eclips创建工程时,你可以指明output或者bin目录,其实IDE就是根据这个参数来放置生成的class文件,同时也会自动从这个目录中开始寻找所需要的类。
上面这段话,其实很直白的告诉我们一个道理,“相对论”是智慧人玩的游戏。不认识你的人想找你,你就不能只说“我在XX房间等你”,如果你们同在一个城市,你可以告诉他“我在XX区XX旅馆XX房间等你”;如果你们在不同的城市甚至不同的国家,你就必须要指定更详细的地址,但无论你们分隔多远,只要你说“我在XX国-XX城市-XX区-XX旅馆-XX房间等你”,他/她想找你就一定能够找到。其实编译器最希望的,就是你明明白白告诉他去哪里找所需要的类。这也是为什么转好JDK后,要设定系统级CLASSPATH环境变量的缘故。你可以打开dt.jar和tools.jar看一看,里面都有哪些包,是不是经常在各种教材上看到过?指定好他们,无论你的JDK安装到哪,这些系统类库总是能够使用的。
同理再扩展一下,有过JavaEE开发经验的兄弟,有没有想过为啥Tomcat这样的Servlet容器,JDBC这样的jar驱动文件只要放到一些固定的目录中,你在源程序中就只需要直接引用就可以了?其实这些容器就是利用了这个原理,只是做了一层二次的封装。
如果明白了这个道理,我们可以回到上文的“第二步”,为什么把编译好的MyFriend.class文件拷贝到main目录中,MyMain.java仍然编译不过。你想啊,MyMain中引用了com.idearye.friend.MyFriend类,而编译的当前目录是什么,是"com\idearye\main",编译器就会傻傻从main目录中去找"com\idearye\friend\MyFriend.class"。编译器不是人,不会像你一样先想想要找的人,跟自己是不是一个城市的一个区一个旅馆的,它只是傻了吧唧的。
这样看,如果你退回到"src",即package的根目录中,直接执行"javac com\idearye\main\MyMain.java",一样编译成功,为啥?就是因为执行javac时的当前目录是src,虽然你没有加上"-sourcepath"和"classpath",但系统环境变量中有"."这个代表当前路径的设置,因此编译器就会从当前目录中同时分别去"com\idearye\main\"和"com\idearye\friend\"中寻找"MyMain.class"和"MyFriend.java"文件,流程同上,当然就能够找到了。这其实是变相告诉编译器相对路径,注意这里是相对路径的概念。
IDE工具就是在利用这些概念,帮你解决了寻找类文件的复杂。所以我们在IDE下面,很简单的做一些事情。写了这么一坨东西,并不代表我喜欢自找麻烦,我依然绝对会继续使用IDE,不会自己写常常的一串路径,我不是偏执狂。
原来的题目本来是"值得写一写的javac与java",其实虚拟机的运行原理和编译器一样,也是这么寻找与定位,因此不再赘述。java命令会有另外几个参数。我建议自己编译和运行时,多使用"-verbose"参数,看一看编译器和虚拟机对类的定位,这是一个挺有趣的东西。回头准备写一写虚拟机类定位的东西,这块也是一个容易被遗忘和忽略的知识点。
好了,全文完,感谢你看了如此多的废话,休息一下眼睛吧。
发表评论
-
Pinterest模式的流行代表着读图时代的到临?
2012-04-02 10:08 658极客公园中看到一篇 ... -
值得写一写的javac(十)
2012-03-21 20:22 0IDE工具就是在利用这些概念,帮你解决了寻找类文件的复杂。所以 ... -
值得写一写的javac(九)
2012-03-21 20:21 0如果明白了这个道理,我们可以回到上文的“第二步”,为什么把编译 ... -
值得写一写的javac(八)
2012-03-21 20:21 0上面这段话,其实很直白的告诉我们一个道理,“相对论”是智慧人玩 ... -
值得写一写的javac(七)
2012-03-21 20:20 0MyMain类中引用了MyFriend类,而MyFriend类 ... -
值得写一写的javac(六)
2012-03-21 20:20 0恩,可以正确编译的程序和编译错误的程序,在于为javac指定了 ... -
值得写一写的javac(五)
2012-03-21 20:18 0或者,我们回到D盘根目录,玩一个跨度更大的!--------- ... -
值得写一写的javac(四)
2012-03-21 20:18 0嘿,当前路径下明明有class文件,而且系统的CLASSPAT ... -
值得写一写的javac(三)
2012-03-21 20:17 0第一步,直接在main目录中编译的后果是:---------- ... -
值得写一写的javac(二)
2012-03-21 20:16 0MyMain.java和MyFriend.java源代码如下: ... -
值得写一写的javac(一)
2012-03-21 20:15 0很多书籍和网络教程关于Java编程环境搭建的内容,一般都言简意 ...
相关推荐
Atom-linter-javac是专为Atom文本编辑器设计的一款插件,用于提供Java语言的实时语法检查功能。Atom是一款由GitHub开发的基于Web技术的开源文本编辑...对于初学者和经验丰富的开发者来说,都是一个值得推荐的插件选择。
Java 编译器,javac,是 Java 语言的核心组成部分,负责将源代码转换成可执行的字节码。深入理解 javac 源码对于提升 Java 开发者的技能至关...这是一次深入底层、增强技术深度的旅程,值得每一个 Java 开发者去探索。
总的来说,"javaC语言试题生成与考试系统"是一个集成了Java编程、C语言教学、数据库管理和在线考试技术的综合性应用,对于教育行业来说,它是一个值得推广的工具,能够推动教育信息化的发展,提升教学质量。...
标题中的“JAVAC5441 学生成绩管理.rar”表明这是一个关于Java编程的项目,具体是用于管理学生成绩的系统。这个系统可能使用了Java和JSP技术来实现,JSP(JavaServer Pages)是Java Web开发中的一种技术,常用于构建...
本例中,会读取一个文本文件,...值得注意的是,javac 命令是 Java 开发工具包 (JDK) 的一部分,而 java 命令则是 Java 运行时环境 (JRE) 的一部分。如果只安装了 JRE 而没有安装 JDK,将无法使用 javac 命令。
值得注意的是,这个编辑器不仅限于文本编辑,它还能直接在内部编译和运行Java代码,这大大简化了开发者的工作流程,无需在多个工具之间切换。 具体来说,编辑器的“打开”功能允许用户从本地文件系统中选择并加载...
在Java编程中,还有一些基本概念值得了解,例如变量(用来存储数据的容器)、数据类型(如整型、浮点型、字符型等)、运算符(如算术运算符、比较运算符、逻辑运算符等)、流程控制(如条件语句if-else,循环语句for...
值得注意的是,尽管Oracle JDK 8u201之后的版本需要付费,但OpenJDK项目提供了一个开源的替代方案,OpenJDK 8和OpenJDK 11等版本仍然提供免费的长期支持。开发者可以选择使用OpenJDK来继续享受Java的最新更新,而...
- `javac`:Java编译器; - `javadoc`:生成文档; - `javap`:Java反汇编器; - `javaw`:无控制台窗口的Java启动器; - `native2ascii`:处理二进制数据到文本的转换; - `serialver`:验证序列化版本。 通过掌握...
Java JDK 11是Oracle公司推出的Java开发工具集的一个重要版本,主要针对开发人员和系统管理员,用于在Linux 64位操作系统上构建、测试和部署Java应用...对于Linux 64位用户来说,这是一个重要的更新,值得安装并使用。
值得注意的是,一个Java源文件可以包含多个类,但最多只能有一个public类,且该类名必须与源文件名相同。 标识符在Java中扮演着重要角色,包括类名、变量名、方法名等。它们的命名规则遵循以下几点: 1. 可以由英文...
Java是一种广泛使用的面向对象的编程语言,以其跨平台性、高效性和丰富的库而著名。在构建一个简单的Java...以上是构建一个Java登录系统涉及的主要知识点,每个方面都值得深入学习和实践,以提升编程技能和软件质量。
值得注意的是,JDK6的`rt.jar`、`tools.jar`等系统库通常无需手动添加到Classpath,因为它们已被默认加载。 编写第一个Java程序通常从创建源文件开始。以“HelloJava.java”为例,文件名必须与主类名相同,并遵循大...
在IT行业中,构建工具是开发过程中的重要环节,它们帮助我们自动化地编译、测试、打包和部署项目。Ant是Apache软件基金会的一个开源项目,它是一个基于...对于熟悉Java和XML的开发者来说,Ant是一个值得掌握的工具。
对于那些依赖Java 8特性的项目来说,这是一个值得信赖的选择,尤其是考虑到它作为甲骨文免费提供的最后一个版本。然而,随着Java 11及更高版本的发布,开发者也需要关注新版本带来的功能更新和长期支持计划。
安装完成后,JDK的bin目录会包含必要的可执行文件,如`javac`(编译器)和`java`(解释器)。 2. **设置JAVA_HOME**:这个环境变量指向JDK的安装目录。例如,如果JDK安装在`C:\Program Files\Java\jdk1.8.0_271`,...
值得注意的是,这里使用了`cf`参数,其中`c`表示创建一个新的JAR文件,`f`表示指定JAR文件名。另外,`-C`参数在创建和更新JAR包时可以用来切换到指定目录下执行jar命令,不过在示例中并没有使用。 最终,生成JAR包...
DOM4J和Jaxen是两个在Java编程中用于XML处理的重要库,它们在解析、操作和查询XML文档方面发挥着关键作用。 DOM4J是一个非常灵活且功能强大的...对于任何涉及到XML操作的Java项目,这两个库都是值得考虑的优秀选择。
然而,值得注意的是,随着Oracle JDK 8的免费支持结束,开发者可能需要考虑迁移到OpenJDK或者其他开源实现,或者购买Oracle的商业支持服务,以确保持续的安全更新。 在使用"jdk-8u191-windows-x64.exe"进行安装时,...