在 Java 中使用包是為了防止命名沖突,來(lái)控制訪問(wèn),使得搜索/定位和類、接口、枚舉和注釋等的使用更為簡(jiǎn)單。
包可以被定義為一組相關(guān)的類型(類、接口、枚舉和注釋),提供訪問(wèn)保護(hù)和命名空間管理。
在 Java 中一些已經(jīng)存在的包有:
java.lang
- 包含了基本類java.io
- 包含有輸入,輸出功能的類程序員可以定義自己的包來(lái)包含各種類和接口等。把你實(shí)現(xiàn)的相關(guān)類組織在一起是一種很好的做法,這樣一個(gè)程序員可以很簡(jiǎn)單的知道哪些類、接口、枚舉,注釋是相關(guān)的。
由于包創(chuàng)建了一個(gè)新的命名空間,因此將不會(huì)和其他包中的名字有任何名字沖突。使用包,可以很簡(jiǎn)單的提供訪問(wèn)控制,并且也可以很簡(jiǎn)單的定位到相關(guān)類。
當(dāng)創(chuàng)建一個(gè)包的時(shí)候,應(yīng)該為包起一個(gè)名字,并且把 package
名字的聲明語(yǔ)句放在每個(gè)包含類、接口、枚舉和注釋類型的源文件頂部。
package
聲明語(yǔ)句應(yīng)該放在源文件的第一行。在每個(gè)源文件中只能有一個(gè)包聲明語(yǔ)句,并且它適用于所有類型的文件。
如果沒(méi)有使用包聲明,那么類、接口、枚舉和注釋類型的將會(huì)被放進(jìn)一個(gè)無(wú)名的包中。
讓我們來(lái)看創(chuàng)建了一個(gè)叫做 Animal
的包的例子。習(xí)慣上使用小寫(xiě)名字的包以避免和類、接口名字的沖突。
在包 animals 中聲明一個(gè)接口:
/* File name : Animal.java */
package animals;
interface Animal {
public void eat();
public void travel();
}
現(xiàn)在,在同一個(gè)包 animals 中實(shí)現(xiàn)一個(gè)類:
package animals;
/* File name : MammalInt.java */
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
現(xiàn)在,你可以編譯這兩個(gè)文件并將它們放置在一個(gè)叫做 animals
的子文件夾中,然后像下述來(lái)運(yùn)行:
$ mkdir animals
$ cp Animal.class MammalInt.class animals
$ java animals/MammalInt
Mammal eats
Mammal travels
如果一個(gè)類想使用同一個(gè)包中的另一個(gè)類,就沒(méi)必要使用包名。同一個(gè)包中的類不用任何特殊的語(yǔ)法就可以彼此識(shí)別。
一個(gè)叫做 Boss 的類添加進(jìn)了已經(jīng)包含了 Employee 的 payroll 包中。 在沒(méi)有使用 payroll 前綴的情況下,Boss 類引用了 Employee 類,像下面演示的 Boss 類:
package payroll;
public class Boss
{
public void payEmployee(Employee e)
{
e.mailCheck();
}
}
如果 Boss 類 沒(méi)有在 payroll 包中會(huì)發(fā)生什么?那么 Boss 類就必須使用下述的其中一種方法來(lái)引用位于其它包中的類。
payroll.Employee
import payroll.*;
import payroll.Employee;
注: 一個(gè)類的文件可以包含任意數(shù)量的導(dǎo)入語(yǔ)句。這些導(dǎo)入語(yǔ)句必須位于包聲明語(yǔ)句之后和類的定義語(yǔ)句之前。
當(dāng)一個(gè)類放置在一個(gè)包中時(shí)主要會(huì)發(fā)生以下兩個(gè)結(jié)果:
在 Java 里有以下一種管理文件的簡(jiǎn)單方式:
將類、接口、枚舉、注釋類型的源代碼存在一個(gè)擴(kuò)展名為 .java
的文本文件中。例如:
// File Name : Car.java
package vehicle;
public class Car {
// Class implementation.
}
現(xiàn)在,將源文件放在一個(gè)其名字能夠反映出包的名字的文件夾中:
....\vehicle\Car.java
現(xiàn)在,正確的類名和路徑名應(yīng)該像下面這樣:
一般情況下,一個(gè)公司使用它的逆序的互聯(lián)網(wǎng)域名當(dāng)做包的名稱。例如:某公司的互聯(lián)網(wǎng)域名是 apple.com ,那么它的包名應(yīng)該是以 com.apple 開(kāi)頭。包名的每一個(gè)部分反映了一個(gè)子目錄。
例如:一個(gè)公司有一個(gè)包含了 Dell.java 源文件的 com.apple.computers 的包,它將被包含在像下面的一系列子文件夾中:
....\com\apple\computers\Dell.java
在編譯的時(shí)候,編譯器為其中定義的每個(gè)類、接口和枚舉創(chuàng)建了一個(gè)不同的輸出文件。輸出文件的基本名字是類型名和 .class
的擴(kuò)展名。
例如:
// File Name: Dell.java
package com.apple.computers;
public class Dell{
}
class Ups{
}
現(xiàn)在,像下面使用 -d 選項(xiàng)來(lái)編譯這個(gè)文件:
$javac -d . Dell.java
這將像下面存放編譯后的文件:
.\com\apple\computers\Dell.class
.\com\apple\computers\Ups.class
你可以像下面這樣導(dǎo)入所有定義在 \com\apple\computers\ 中的類和接口:
import com.apple.computers.*;
像 .java 這樣的源文件, .class 這些編譯后的文件應(yīng)該在能夠反映出包名的一系列文件夾中。然而, .class 文件的路徑不用和 .java 源文件的路徑相同。你可以獨(dú)立的管理源文件和編譯后文件的目錄,如下:
<path-one>\sources\com\apple\computers\Dell.java
<path-two>\classes\com\apple\computers\Dell.class
通過(guò)這樣,可以把編譯過(guò)后的文件夾給其它的程序員而不用暴露你的源文件。同時(shí)你也需要使用這種方式來(lái)管理源文件和編譯過(guò)后的 class 文件以便編譯器和 Java 虛擬機(jī)(JVM)能夠找到程序中使用的所有類型。
編譯后文件夾的全路徑, \
我們說(shuō) \
一個(gè) class path 可能包含幾個(gè)路徑。多個(gè)路徑以分號(hào)(Windows)或者冒號(hào)(Unix)隔開(kāi)。默認(rèn)情況下,編譯器和 JVM 查找當(dāng)前目錄和包含 Java 平臺(tái)字節(jié)碼的 JAR 文件以便于這些文件夾自動(dòng)在 class path 中。
為了顯示當(dāng)前的 CLASSPATH 環(huán)境變量,使用以下在 Windows 和 UNIX(Bourne shell)中的命令:
使用下述命令刪除當(dāng)前 CLASSPATH 變量中的內(nèi)容:
使用下述命令設(shè)置 CLASSPATH 變量: