Java 套件(package)


為了更好地組織類,Java提供了套件機制,用於區別類別名稱的命名空間。

套件的作用

  • 1 把功能相似或相關的類別或介面組織在同一個套件中,方便類別的尋找和使用。

  • 2 如同資料夾一樣,套件也採用了樹狀目錄的儲存方式。同一個套件中的類別名字是不同的,不同的套件中的類別的名字是可以相同的,當同時呼叫兩個不同套件中相同類別名稱的類別時,應該加上套件名稱加以區別。因此,包可以避免名字衝突。

  • 3 套件也限定了存取權限,擁有套件存取權限的類別才能存取某個套件中的類別。

Java使用套件(package)這種機制是為了防止命名衝突,存取控制,提供搜尋和定位類別(class)、介面、枚舉(enumerations)和註解(annotation )等。

套件語句的語法格式為:

package pkg1[.pkg2[.pkg3…]];

例如,一個Something.java 檔案它的內容

package net.java.util
public class Something{
   ...
}

那麼它的路徑應該是net/java/util/Something .java 這樣保存的。 package(套件)的作用是把不同的java程式分類保存,更方便的被其他java程式呼叫。

一個套件(package)可以定義為一組相互聯繫的類型(類別、介面、枚舉和註解),為這些類型提供存取保護和命名空間管理的功能。

以下是一些Java中的套件:

  • java.lang-打包基礎的類別

  • java.io-包含輸入輸出功能的函數

開發者可以自己把一組類別和介面等打包,並定義自己的package。而且在實際開發中這樣做是值得提倡的,當你自己完成類別的實作之後,將相關的類別分組,可以讓其他的程式設計者更容易確定哪些類別、介面、枚舉和註解等是相關的。

由於package創造了新的命名空間(namespace),所以不會跟其他package中的任何名字產生命名衝突。使用套件這種機制,更容易實現存取控制,並且讓定位相關類別更加簡單。


建立套件

建立package的時候,你需要為這個package取一個合適的名字。之後,如果其他的一個原始檔案包含了這個套件提供的類別、介面、枚舉或註解類型的時候,都必須將這個package的聲明放在這個原始檔的開頭。

套件聲明應該在原始檔案的第一行,每個來源檔案只能有一個套件聲明,這個檔案中的每個類型都套用到它。

如果一個來源檔案中沒有使用套件聲明,那麼其中的類,函數,枚舉,註解等將被放在一個無名的套件(unnamed package)中。

範例

讓我們來看一個例子,這個例子建立了一個叫做animals的套件。通常使用小寫的字母來命名避免與類別、介面名字的衝突。

在animals套件中加入一個介面(interface):

/* 文件名: Animal.java */
package animals;

interface Animal {
   public void eat();
   public void travel();
}

接下來,在同一個套件中加入該介面的實作:

package animals;

/* 文件名 : 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();
   }
}

然後,編譯這兩個文件,並把他們放在一個叫做animals的子目錄中。 用下面的指令來執行:

$ mkdir animals
$ cp Animal.class  MammalInt.class animals
$ java animals/MammalInt
Mammal eats
Mammal travel

import關鍵字

為了能夠使用某一個套件的成員,我們需要在 Java 程式中明確匯入該套件。使用"import"語句可完成此功能。

在java 原始檔中import 語句應位於package 語句之後,所有類別的定義之前,可以沒有,也可以有多條,其語法格式為:

import package1[.package2…].(classname|*);

如果在一個包中,一個類別想要使用本包中的另一個類,那麼該包名可以省略。

範例

下面的payroll套件已經包含了Employee類,接下來在payroll套件中加入一個Bo​​ss類別。 Boss類別引用Employee類別的時候可以不用使用payroll前綴,Boss類別的實例如下。

package payroll;

public class Boss
{
   public void payEmployee(Employee e)
   {
      e.mailCheck();
   }
}

如果Boss類別不在payroll套件中又會怎樣? Boss類別必須使用下面幾種方法之一來引用其他套件中的類別

使用類別全名描述,例如:

payroll.Employee

用import關鍵字引入,使用通配符"*"

import payroll.*;

使用import關鍵字引入Employee類別

import payroll.Employee;

注意:

類別檔案中可以包含任意數量的import聲明。 import聲明必須在套件聲明之後,類別聲明之前。


package的目錄結構

類別放在包包中會有兩個主要的結果:

  •                 包名成為類別名稱的一部分,正如我們前面討論的一樣。

  •                 包名必須與對應的字節碼所在的目錄結構相吻合。

下面是管理你自己java中檔案的簡單方式:

將類別、介面等類型的原始碼放在一個文字中,這個檔案的名字就是這個類型的名字,並以.java作為副檔名。例如:

// 文件名 :  Car.java

package vehicle;

public class Car {
   // 类实现  
}

接下來,把來源檔案放在一個目錄中,這個目錄要對應類別所在套件的名字。

....\vehicle\Car.java

現在,正確的類別名稱和路徑將會是以下樣子:

  • #類別名稱->  vehicle.Car

  • #路徑名->   vehicle\Car.java (in windows)

通常,一個公司使用它互聯網域名的顛倒形式來作為它的包名.例如:互聯網域名是apple.com,所有的套件名稱都以com.apple開頭。包名中的每一個部分對應一個子目錄。

例如:這個公司有一個com.apple.computers的包,這個包包含一個叫做Dell.java的源文件,那麼相應的,應該有如下面的一連串子目錄:

....\com\apple\computers\Dell.java

編譯的時候,編譯器為包中定義的每個類別、介面等類型各創建一個不同的輸出文件,輸出文件的名字就是這個類型的名字,並加上.class作為擴展後綴。 例如:

// 文件名: Dell.java

package com.apple.computers;
public class Dell{
      
}
class Ups{
      
}

現在,我們用-d選項來編譯這個文件,如下:

$javac -d . Dell.java

這樣會像下面這樣放置編譯了的文件:

.\com\apple\computers\Dell.class.\com\apple\computers\Ups.class

你可以像下面這樣來導入所有\com\apple\computers\中定義的類別、介面等:

import com.apple.computers.*;

編譯之後的.class檔案應該和.java原始檔一樣,它們放置的目錄應該跟包的名字對應。但是,並不要求.class檔案的路徑跟對應的.java的路徑一樣。你可以分開來安排原始碼和類別的目錄。

<path-one>\sources\com\apple\computers\Dell.java
<path-two>\classes\com\apple\computers\Dell.class

這樣,你可以將你的類別目錄分享給其他的程式設計人員,而不用透露自己的原始碼。用這個方法管理原始碼和類別檔案可以讓編譯器和java虛擬機器(JVM)可以找到你程式中使用的所有類型。

類別目錄的絕對路徑叫做class path。設定在系統變數CLASSPATH中。編譯器和java虛擬機器透過將package名字加到class path後來建構.class檔案的路徑。

<path- two>\classes是class path,package名字是com.apple.computers,而編譯器和JVM會在<path-two>\classes\com\apple\compters中找.class文件。

一個class path可能會包含好幾個路徑。多路徑應該用分隔符號分開。預設情況下,編譯器和JVM會尋找目前目錄。 JAR檔案依照包含Java平台相關的類,所以他們的目錄預設放在了class path。


設定CLASSPATH系統變數

用下面的指令顯示目前的CLASSPATH變數:

  •                 Windows平台(DOS 指令列下)-> C:\> set CLASSPATH

  •                 UNIX平台(Bourne shell下)-> % echo $CLASSPATH

#刪除目前CLASSPATH變數內容:
  •                Windows平台(DOS 命令列下)-> C:\> set CLASSPATH=

  •                 UNIX平台(Bourne shell下)-> % unset CLASSPATH; export CLASSPATH

設定CLASSPATH變數:

  •          Windows平台(DOS 命令列下)-> set CLASSPATH=C:\users\jack\java\classes

  •                 UNIX平台(Bourne shell下)-> % CLASSPATH=/home/jack/java/classes; export CLASSPATH