C:/myjob> 然后我们在src目录中去写程序 C:/myjob>cd src C:/myjob/src>
我们写这么4个java文件 A.java package com.lightning; public class A{ public static void main(String[] args){ System.out.println("com.lightning.A"); } }
B.java package com.lightning; public class B{ public static void main(String[] args){ System.out.println("com.lightning.B"); } }
C.java package com; public class C{ public static void main(String[] args){ System.out.println("com.C"); } } Test.java package net.test; import com.lightning.*; import com.*; public class Test{ public static void main(String[] args) { new A();new B();new C(); System.out.println("net.test.Test"); } } 写好之后就是这样 C:/myjob/src>dir 驱动器 C 中的卷是 LIGHTNING 卷的序列号是 3DD1-83D9 C:/myjob/src 的目录 2005-12-25 14:34 . 2005-12-25 14:34 .. 2005-12-25 14:39 86 A.java 2005-12-25 14:40 86 B.java 2005-12-25 14:42 194 Test.java 2005-12-25 14:43 68 C.java 4 个文件 434 字节 2 个目录 305,106,944 可用字节 然后我们建立com目录,com/lightning/目录,net/test/目录 C:/myjob/src>md com C:/myjob/src>md com/lightning C:/myjob/src>md net/test/
我们将Test.java放入net/test/中去,将A.java,B.java放入com/lightning/中去,将C.java放入com/中去 C:/myjob/src>move Test.java net/test/ C:/myjob/src>move A.java com/lightning/ C:/myjob/src>move B.java com/lightning/ C:/myjob/src>move C.java com/ 然后我们在c:/myjobs中发令: C:/myjob/src>cd .. C:/myjob>javac -sourcepath src -d bin src/net/test/Test.java 然后我们看看bin目录中多了什么 C:/myjob>dir bin /s 驱动器 C 中的卷是 LIGHTNING 卷的序列号是 3DD1-83D9 C:/myjob/bin 的目录 2005-12-25 14:34 . 2005-12-25 14:34 .. 2005-12-25 14:46 net 2005-12-25 14:46 com 0 个文件 0 字节 C:/myjob/bin/net 的目录 2005-12-25 14:46 . 2005-12-25 14:46 .. 2005-12-25 14:46 test 0 个文件 0 字节 C:/myjob/bin/net/test 的目录 2005-12-25 14:46 . 2005-12-25 14:46 .. 2005-12-25 14:46 520 Test.class 1 个文件 520 字节 C:/myjob/bin/com 的目录 2005-12-25 14:46 . 2005-12-25 14:46 .. 2005-12-25 14:46 lightning 2005-12-25 14:46 338 C.class 1 个文件 338 字节 C:/myjob/bin/com/lightning 的目录 2005-12-25 14:46 . 2005-12-25 14:46 .. 2005-12-25 14:46 354 A.class 2005-12-25 14:46 354 B.class 2 个文件 708 字节 所列文件总数: 4 个文件 1,566 字节 14 个目录 305,057,792 可用字节 然后我们执行,同样在c:/myjobs/下发令 C:/myjob>java -cp bin net.test.Test com.lightning.A com.lightning.B com.C net.test.Test 2,从实践到理论 刚才我用一个非常简单但是非常完整的例子给大家演示了java的package机制。为什么以前脑海里面那么简单的javac会搞得这么复杂呢?实际上它本就这么复杂,并不是一个.java,一行javac一个当前目录中的class这么简单。 首先我要打破一些东西,然后才好建立一些东西。 javac并非只是给一个.java编译一个class的。javac自带有make机制,也就是说,如果在javac的参数中java文件使用到的任何类,javac首先会去找寻这个类的class文件存在与否,如果不存在,就会在sourcepath中找寻源代码文件来编译。 什么是sourcepath呢?sourcepath是javac的一个参数,如果你不加指定,那么sourcepath就是classpath。 比如我们装好jdk之后,我说过不要设定classpath环境变量,因为大部分人一旦设定了classpath,不是多此一举把什么dt.jar放进去。(我可以好好打击你一下,告诉你一个可悲的事实——jre永远不会从你这个classpath中去寻找dt.jar。你完全是徒劳的!)就是 把"."搞不见了,搞得是冷水一盆盆的往自己身上泼,脑袋一点点的涨大。 不要设!classpath没有你想象中那么普适和强大,它只是命令行的简化替代品。 你不设的话它就是"."。 回到sourcepath,sourcepath指的是你源代码树的存放地点。为什么是源代码树?而不是一个目录的平板源代码呢? 请大家将原本脑海中C的编译过程完全砸掉!java完全不同,java没有头文件,每个.java都是要放在源代码树中的。那么这颗树是怎么组织的呢?对了,就是package语句。比如写了package com.lightning;那么这个.java就必须放在源代码树根/的com/lighting/之下才行。 很多浮躁的初学者被default打包方式宠坏了。自我为中心,以为java就是一套库,自己写的时候最多import进来就行了,代码从不打包,直接javac,直接java,多么方便。孰不知自己写的这个.java也不过是java大平台的其中一个小单元而已。如果不打包,我写一个Point,你写一个Point,甚至更有甚者敢于给自己的类起名叫String等等。全部都在平板式的目录中,那jre该选哪一个? 一旦要使用package语句,就要使用代码树结构,当然,你要直接javac,也行。不过javac出来的这个class要放在符合package结构的目录中才能发挥正常作用,否则就是废物一坨。而且,如果你这个.java还用到其它自己写的有package语句的.java,那这个方法就回天乏术了。 按照sun的想象,应该是写好的.java放在符合package结构的目录中,package语句保证了正确放置,如果目录位置和package语句中指示的不同,则会出错。 所以按照刚才我们的那种package写法,我们必然要将那几个.java文件放入相应的目录中才能让javac顺利找到他们来make。 有人说javac可不可以像java那样 java aaa.bbb.c...java? 不可以 javac中的那个.java文件参数必须是一个文件系统的路径文件名形式。 然后如果用到其它的.java,javac会根据目前的sourcepath出发寻找目录结构中的那些java文件。 当然了,既然打了包,在使用的时候。 要么写全名——包名.类名 或者使用import 不得不提的是,import就好比c++的using,它不负责做文件操作,它只是方便你写代码。 另外import中的*代表的是类名,不代表包名片断。 你import com.*; 编译器仍然找不到com.lightning中的任何类。 反之亦然。就好象你告诉编译器,我这里面要用到姓诸葛的人。那么姓诸的人当然编译器不会认为也包含在内。 所以,如果程序一旦写到一定规模。就不得不使用ant来管理这些。或者使用IDE,否则jdk就真的变成了java developer killer。 但是对于初学者,在了解为什么会有ant之类的之前,还是要体会一下使用 jdk的艰辛。 这个和以前在unix上开发的人用gcc命令行到后来使用make之后使用ide之类的时候的体会是类似的。 最后,javac的-d参数是指示编译出来的class文件放在哪里的,如果你不指定的话,它们和.java混在一起。当然也符合目录结构。 |