创建自己的包时,要求package语句必须是文件中的第一个“非注释”代码。第二个文件表面看起来是类似的:
7 x" j& |" W2 w1 Q //: List.java
- u$ o! l, [" m" l( G4 |3 B2 g // Creating a package$ T# t( W2 {. C: H; i: G* l
package com.bruceeckel.util;
! l- `; ]7 G7 [ public class List {7 ?+ y) e' m, X! {7 |- g) i
public List() {- U B3 p# p+ K* p. J
System.out.println(
1 b o( O S1 D$ P: s, A% o "com.bruceeckel.util.List");% S/ c" l$ P( d
}
1 }+ ]% }/ }1 d; L3 ^/ [8 F. m( }+ T5 N } ///:~
9 x2 I: D" V/ j1 P" Q6 x; h 这两个文件都置于我自己系统的一个子目录中:
7 { @9 Q; K" L4 ~" X* V4 Y C:\DOC\JavaT\com\bruceeckel\util
( h' T0 |$ H- D2 \& [+ u4 n- i: } 若通过它往回走,就会发现包名com.bruceeckel.util,但路径的第一部分又是什么呢?这是由CLASSPATH环境变量决定的。在我的机器上,它是:
" Z2 W7 k# v( Q3 B% _9 B CLASSPATH=.;D:\JAVA\LIB;C:\DOC\JavaT4 l) U g$ n( M' K+ u# _
可以看出,CLASSPATH里能包含大量备用的搜索路径。然而,使用JAR文件时要注意一个问题:必须将JAR文件的名字置于类路径里,而不仅仅是它所在的路径。所以对一个名为grape.jar的JAR文件来说,我们的类路径需要包括:( p/ L! k* [, C8 J; m) E' Z
CLASSPATH=.;D:\JAVA\LIB;C:\flavors\grape.jar
6 W% D7 a- `9 `/ E& G! i 正确设置好类路径后,可将下面这个文件置于任何目录里(若在执行该程序时遇到麻烦,请参见第3章的3.1.2小节“赋值”):" f5 V7 v$ j ]4 a3 Q$ w* a) w" `
//: LibTest.java
; m, f$ |, o; Y // Uses the library
1 B2 L3 w, C3 [3 i4 z package c05;
3 ~; f) H0 E# F L import com.bruceeckel.util.*;
% f$ L" E' J0 `+ z2 [ public class LibTest {( `) k& N, E- S7 s; ?
public static void main(String[] args) {
7 i& i% o# U6 ]; ^0 y5 P Vector v = new Vector();( x( n" i9 h# y( M9 r* H
List l = new List();( ~ g! q0 C) l- {1 x' _, ?
}
$ b; \. f" s; f2 y6 o# U& y, U } ///:~
+ Q+ F: p2 t9 t5 \ 编译器遇到import语句后,它会搜索由CLASSPATH指定的目录,查找子目录com\bruceeckel\util,然后查找名称适当的已编译文件(对于Vector是Vector.class,对于List则是List.class)。注意Vector和List内无论类还是需要的方法都必须设为public。0 G. q+ U7 f ~- t) F; K
1. 自动编译1 z6 s/ p2 D$ ~* j L" ]4 ^; M
为导入的类首次创建一个对象时(或者访问一个类的static成员时),编译器会在适当的目录里寻找同名的.class文件(所以如果创建类X的一个对象,就应该是X.class)。若只发现X.class,它就是必须使用的那一个类。然而,如果它在相同的目录中还发现了一个X.java,编译器就会比较两个文件的日期标记。如果X.java比X.class新,就会自动编译X.java,生成一个最新的X.class。
* V0 B4 [2 H0 a1 T* F+ | 对于一个特定的类,或在与它同名的.java文件中没有找到它,就会对那个类采取上述的处理。: X1 \# q: F2 ]3 S
2. 冲突4 ^- z+ A! A1 P' K# E8 l) P$ I
若通过*导入了两个库,而且它们包括相同的名字,这时会出现什么情况呢?例如,假定一个程序使用了下述导入语句:
6 b& [+ E0 n+ t# l import com.bruceeckel.util.*;8 R! E% k1 t* Y1 p7 u' L& _' _0 \1 ^
import java.util.*;
/ J% F6 ^7 m5 _4 S. S, u' p. F- w 由于java.util.*也包含了一个Vector类,所以这会造成潜在的冲突。然而,只要冲突并不真的发生,那么就不会产生任何问题——这当然是最理想的情况,因为否则的话,就需要进行大量编程工作,防范那些可能可能永远也不会发生的冲突。
! I, `5 p* u5 t- L* y6 B 如现在试着生成一个Vector,就肯定会发生冲突。如下所示:
- q k( s! x% ]( Y( | v% y$ I Vector v = new Vector();
6 L( O! f! o$ r1 D 它引用的到底是哪个Vector类呢?编译器对这个问题没有答案,读者也不可能知道。所以编译器会报告一个错误,强迫我们进行明确的说明。例如,假设我想使用标准的Java Vector,那么必须象下面这样编程:
+ b9 |3 \3 r# W- h$ }# K) P java.util.Vector v = new java.util.Vector();% o. U- H1 R3 q, }* A! J! w
由于它(与CLASSPATH一起)完整指定了那个Vector的位置,所以不再需要import java.util.*语句,除非还想使用来自java.util的其他东西。 |