在Java中,Package是用來包含一系相關實例的集合。這些相關聯的實例包括:類、接口、異常、錯誤以及枚舉。html
Package主要有一些的幾點做用:java
Package能夠處理名字衝突,在衝突的名字前加上包的名字,經過使用名字的全限定名來訪問名字的時候,能夠避免名字衝突。由於在不一樣的包之間,具備不一樣的包名,因此能夠經過全限定名來區分不一樣包中同名的名字。Package的這種機制稱爲名字空間管理(Namespace Management)。bootstrap
Package能夠實現訪問控制,在Java中,除了經常使用的public
和private
這兩個訪問控制修飾符外,還包含了protected
和default
這兩個訪問控制修飾符,這兩個修飾符都和Package相關。經過protected
修飾的實體,它的訪問受限於同一個包和它的子類中。若是一個實體沒有包含任何的訪問控制修飾符,那麼默認就是default
,它的訪問受限於同一個包中。bash
用於發佈可重用的類的集合,一般會將這些類打包成JAR包的形式。oracle
一個包的名字能夠經過將互聯網的域名反向後加上本身的項目名字產生。中間經過.
進行分隔。Package的名字採用小寫的方式。(i.e. 若是一我的的域名是'abc.com',那麼他能夠將本身項目的包名寫成 'com.abc.project')。ide
咱們可能會看到在Java官方提供的包中,包含了java
和javax
前綴的包名,這兩個前綴分別用於官方提供的java包和java的擴展包。工具
Java中的包名和文件系統的目錄結構之間是有聯繫的。同一個包中的實體,都被存儲在同一個目錄下,確切的說,這些實體被存儲在經過包名肯定的子目錄結構下。i.e.,假設存在一個包名爲 com.abc.project
的包,那麼這個包中的實體被存儲在目錄$BASE_DIR/com/abc/project
下,其中的$BASE_DIR
表示了包的根目錄,也能夠稱爲Java中的類路徑。經過上面的例子,咱們能夠發現,將包名中的.
轉換爲/
就是相應的子目錄結構了。開發工具
上面提到的$BASE_DIR
能夠存在於文件系統的任何位置,因此Java的編譯器和虛擬機必須知道$BASE_DIR
的位置,才能夠定位到須要的實體。對這個位置的查找是經過環境變量CLASSPATH
來實現的。CLASSPATH
是一個相似於PATH
的環境變量,只是CLASSPATH
是用於查找Java的類的位置的。優化
在Java中,沒有子包的概念。i.e.,兩個包java.awt
和java.awt.event
,這兩個包具備相同的前綴。其中包java.awt
中的實體存儲在路徑$BASE_DIR\java\awt
下,而包java.awt.event
中的實體存儲在路徑$BASE_DIR\java\awt\event
下,這是兩個獨立的包,只是具備相同的前綴而已,因此java.awt.event
不是java.awt
的子包。ui
package com.yyy; public class Circle { private double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } }
咱們在./src/java/com/yyy
目錄下建立了一個com.yyy
的包,而且在包中建立了一個Circle類。而後咱們須要將這個類的編譯後的class文件存儲在目錄classes
目錄下。
javac -d ./classes ./src/java/com/yyy/Circle.java
javac
命令會編譯這個java文件,而後將編譯後的class文件存儲在classes/com/yyy
目錄下,com/yyy
這個子目錄會根據包名com.yyy
自動生成。在這裏,咱們經過選項-d
來指定生成的類存放的位置的根目錄。
下面,咱們使用上面建立的類對象:
import com.yyy.Circle; public class TestCircle { public static void main(String[] args) { Circle c = new Circle(1.23); System.out.println(c.getRadius()); } }
咱們在目錄./test
下建立類TestCircle
,可是咱們不能直接編譯這個類:
cd test javac TestCircle.java
上面的命令會報錯,提示找不到類com.yyy.Circle
,因此咱們須要告訴編譯器該類的位置。經過選項-cp(-classpath)
能夠指定類路徑的位置(這個路徑是包所在的根目錄,而不是包中類的目錄。經過這個根目錄,java會自動查找包中的類)。
javac -cp ./classes TestCircle.java
經過-cp
指定類路徑之後,能夠順利編譯經過了,可是若是咱們直接執行生成的class文件,仍是會出現問題:
java TestCircle
上面的命令會報錯,提示找不到類com.yyy.Circle
,因此咱們須要告訴命令哪裏能夠找到這個類,跟上面同樣,給出這個類所在的位置,也就是類路徑:
java -cp ./classses TestCircle
上面的命令,看似沒什麼問題了,可是運行仍是會報錯,可是此次提示找不到TestCircle類。這是由於java的CLASSPATH
若是沒有被顯式定義指定,那麼默認值是當前目錄,因此第一次沒有報找不到TestCircle的錯誤。可是若是咱們顯式更改CLASSPATH
的值(經過上面的-cp選項),那麼就默認不會包含當前的目錄,若是須要包含當前的目錄,則須要顯式指定。在CLASSPATH
中能夠經過:
分隔不一樣的路徑。
java -cp .:./classes TestCircle
若是TestCircle.java
被定義在包com.abc
中,那麼若是咱們在這個包的根目錄下引用這個類,則須要使用這個類的全限定名:
//TestCircle.java和Circle.java的class文件都被放在classes目錄下 javac -d classes -cp ./classes src/com/abc/TestCircle.java //咱們當前所在的目錄是包的根目錄,因此引用TestCircle的時候,須要使用全限定名 java -cp ./classes com.abc.TestCircle
CLASSPATH
是一個環境變量,Java虛擬機和編譯器會經過這個環境變量來查找java類和包的位置。
在討論Java的CLASSPATH環境變量以前,先介紹下Java虛擬機是如何查找Class文件的。
java虛擬機,也就是java
命令,經過如下的順序查找和加載java的class文件:
-classpath(-cp)
選項來指定,或者經過設置環境變量CLASSPATH
來指定。Bootstrap classes是一些用於實現Java 2平臺的class文件。Bootstrap classes包含在rt.jar和一些其餘的jar文件中,這些jar文件放在jre/lib
目錄下。這些包是經過bootstrap class路徑指定的,這個路徑值存儲在sun.boot.class.path
這個系統屬性中,這個系統屬性應該是隻讀的,不該該直接修改。
通常狀況下,bootstrap classes路徑是不該該被從新修改的。Java的非標準選項-Xbootclasspath
,容許修改這個路徑值來進行自定義定製核心class。
須要指出的是,實現Java 2 SDK的工具class文件並不和bootstrap class文件存放在一塊兒。這些工具sdk存放在目錄/lib/tools.jar
下。開發工具會在啓動Java虛擬機的時候將這個jar包添加到user class路徑中。然而,這個加強的user class路徑只是用於執行這些工具,對於處理源代碼的工具,如javac
和javadoc
,它們使用的是原始的class路徑,而不是這個加強版本的class路徑。
Extension classes是一些用於擴展Java平臺的class文件。這些用於擴展Java平臺的class文件被組織成jar包的形式,存儲在jre/lib/ext
目錄下。在這個目錄下的jar文件會經過Java Extension Framework進行加載。在這個目錄下的鬆散的class文件不會被查找,這些class文件必須是以jar/zip包的形式打包之後才能夠被查找。這個擴展包存放的目錄的位置是不能被修改的。
在目錄jre/lib/ext
目錄下若是存在多個jar文件,而且這些jar包中包含了同名的class文件,如:
smart-extension1_0.jar contains class smart.extension.Smart smart-extension1_1.jar contains class smart.extension.Smart
那麼,具體加載上面哪一個smart.extension.Smart類是未定義的。
Uesr Classes是一些在java平臺上建立的class文。Java虛擬機經過引用 user class path 來查找這些class文件的位置, user class path 是一個包含了class文件的目錄、jar包和zip包的路徑列表。
一個class文件擁有一個反映類的全限定名的子路徑名,如:假設有一個名爲com.mypackage.MyClass
的類,而且存放在目錄/myClasses
下,那麼目錄myClasses
必須在 user class path 中,而且MyClass這個類的路徑必須是/myClasses/com/mypackage/MyClass.class
。若是這個類被存儲在myclasses.jar
這個jar包中,那麼myclasses.jar
這個包必須在 user class path 中,而且這個類在jar包中的路徑必須是com/mypackage/MyClass.class
。
用戶類路徑,也就是 user class path ,是以字符串的形式指定的,在Unix下經過:
進行分隔,而Win下使用;
進行分隔。Java虛擬機會將用戶類路徑中的字符串添加到java.class.path
系統屬性中,這個屬性的值有幾種設置途徑:
.
,表示當前目錄CLASSPATH
的值,這個值會覆蓋默認值。-cp / -classpath
選項指定的路徑值,這個值會覆蓋默認值和CLASSPATH
環境變量的值。-jar
選項指定的jar包的路徑值,這個值會覆蓋上面全部的值,若是這個選項被設置,那麼全部的用戶類必須經過jar包的形式指定。經過上面列出的規則,咱們能夠知道,CLASSPATH
環境變量的值只是Java查找類的一中方式。
一個jar包文件一般包含一個稱爲manifest
的文件,這個文件包含了這個jar包中的內容。這個manifest文件能夠定義一個稱爲JAR-class-path
的類路徑,這個類路徑能夠用於擴展Java的類路徑(前提是這個jar包被加載進來)。經過JAR-class-path
訪問類的順序定義以下:
http://docs.oracle.com/javase/7/docs/technotes/tools/findingclasses.html
http://www.ntu.edu.sg/home/ehchua/programming/java/J9c_PackageClasspath.html