“包”這個機制,類似于分組。主要作用是區分不同組內的同名類。例如,高三三班有一個“王五”,高二八班也有一個“王五”。高三三班和高三八班就是兩個不同的包。
Java中的包(package)機制主要提供了類的多層命名空間,用于解決類的命名沖突、類文件管理等。
類似于C++中的命名空間
namespace
。
如果希望把一個類放在指定的包結構下,應該在Java源程序的第一個非注釋行聲明:
package packageName;
一旦如上聲明,這個源文件中所有定位的類都屬于這個包。
如果其他人要使用這個類,需要使用這個類的完整名稱:包名+類名。
// 文件:Hello.java
package lee;
public class Hello
{public static void main(String[] args){// TODO}
}
如果使用如下命令來編譯
javac -d . Hello.java
按道理,-d是指定編譯結果.class文件的位置,這里指定是當前目錄(.),但實際上是在當前路徑下創建了一個文件夾lee,里面包含Hello.class。
這是因為,Java規定位于包中的類,在文件系統中也必須有與包名層次相同的目錄結構。
但是,如果直接使用javac Hello.java
不會創建lee文件夾。這樣做也屬于挑戰智商的行為,一般還是推薦使用-d,讓它形成層次目錄結構。
在執行的時候,需要給出這個類的完整名稱:
java lee.Hello
虛擬機在裝載lee.Hello類時,會依次搜索CLASSPATH環境變量所指定的系列路徑,查找這些路徑下是否包含lee路徑,并在lee路徑下查找是否包含Hello.class文件。同一個包中的類不必位于相同路徑下,只要它們都在CLASSPATH環境變量中即可。例如lee.Person可以在C盤中,lee.PersonTest可以在D盤中。
另外,除了類文件組織成層次結構外,源文件也要組織成對應的層次結構。此外,建議把源文件和class文件分開放:
把class文件放到某個目錄下,并不意味這個目錄成了這個類的包名。必須在Java源文件中聲明package來指定。
Java包機制運行需要兩個條件:
- 在源文件中打包(package packageName);
- class文件位于對應路徑下(這個一般通過編譯器來自動管理)。
對于包重名的情況,建議包也可以通過層級來組織,比如
org.crazyit.elearning.student.lee
云云。
package的使用有如下注意事項:
- 必須是源文件中非注釋的第一句;
- 一個源文件只能指定一個包;
- 如果沒有顯示指定包,則類位于默認包下;
- 同一個包下的類可以自由訪問。
// HelloTest.java
package lee;
public class HelloTest
{public static void main(String[] args){// 直接訪問相同包下的類,不需要使用包前綴var h = new Hello();}
}
如果在lee包下再定義一個子包,那么子包中的類不能直接訪問lee包中的類了。此外,在使用子包中的類時,要使用該類的全名(包名+類名),不能省略前面lee包的路徑。
package lee.sub;
public class Apple{}
在lee.Hello
中使用Apple類時,必須用完整路徑lee.sub.Apple
。
可以這么理解:父包和子包從邏輯上存在上下關系;但是從用法上沒有任何關系。所以調用時要使用完整包名+類名。
package lee;
public class Hello
{public static void main(String[] args){var a = new lee.sub.Apple(); // 使用完整路徑}
}
為了簡化對不用包的類的調用,Java引入了import
關鍵字。import
可以導入指定包層次下的某個類或全部類。
import
在package
之后,類定義之前;- 一個Java源文件只能有一個
package
,但是可以有多個import
。
import lee.sub.Apple; // 導入lee.sub中的Apple類
import lee.sub.* // 導入lee.sub中的所有類
使用import
后,在當前源文件中就不用再輸入完整路徑了。
這一條和C++中的
using namespace
類似。
Java默認所有源文件都導入了
java.lang
包下的所有類。所以String, System類不需要顯示的import。
import語句可以簡化編程,但并不是必需的。
JDK 1.5之后,還允許使用import
導入類成員變量、類方法,區別在于加上了static
修飾符:
import static package.subpackage.className.fieldName|methodName;
例如,使用import static
導入java.lang
包中System類和Math類的所有靜態成員和靜態方法(類成員和類方法):
import static java.lang.System.*;
import static java.lang.Math.*;public class StaticImportTest
{public static void main(String[] args){// out是System的成員方法;// PI是Math類的成員變量;out.println(PI);}
}
現在總結Java源文件的大致結構:
package 語句; // 0或者1條,位于文件非注釋行的最開始
import | import static 語句; // 0條或者多條,位于package之后,第一個public類定義之前
public className | interfaceName | enumName; //0個或者1個public類、接口或枚舉,注意一個源文件只能有1個public類
className | interfaceName | enumName; // 0個或多個普通類、接口或枚舉,可以有,也可以沒有