程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 創建獨一無二的包名

創建獨一無二的包名

編輯:關於JAVA

大家或許已注意到這樣一個事實:由於一個包永遠不會真的“封裝”到單獨一個文件裡面,它可由多個.class文件構成,所以局面可能稍微有些混亂。為避免這個問題,最合理的一種做法就是將某個特定包使用的所有.class文件都置入單個目錄裡。也就是說,我們要利用操作系統的分級文件結構避免出現混亂局面。這正是Java所采取的方法。
它同時也解決了另兩個問題:創建獨一無二的包名以及找出那些可能深藏於目錄結構某處的類。正如我們在第2章講述的那樣,為達到這個目的,需要將.class文件的位置路徑編碼到package的名字裡。但根據約定,編譯器強迫package名的第一部分是類創建者的因特網域名。由於因特網域名肯定是獨一無二的(由InterNIC保證——注釋②,它控制著域名的分配),所以假如按這一約定行事,package的名稱就肯定不會重復,所以永遠不會遇到名稱沖突的問題。換句話說,除非將自己的域名轉讓給其他人,而且對方也按照相同的路徑名編寫Java代碼,否則名字的沖突是永遠不會出現的。當然,如果你沒有自己的域名,那麼必須創造一個非常生僻的包名(例如自己的英文姓名),以便盡最大可能創建一個獨一無二的包名。如決定發行自己的Java代碼,那麼強烈推薦去申請自己的域名,它所需的費用是非常低廉的。

②:ftp://ftp.internic.net

這個技巧的另一部分是將package名解析成自己機器上的一個目錄。這樣一來,Java程序運行並需要裝載.class文件的時候(這是動態進行的,在程序需要創建屬於那個類的一個對象,或者首次訪問那個類的一個static成員時),它就可以找到.class文件駐留的那個目錄。
Java解釋器的工作程序如下:首先,它找到環境變量CLASSPATH(將Java或者具有Java解釋能力的工具——如浏覽器——安裝到機器中時,通過操作系統進行設定)。CLASSPATH包含了一個或多個目錄,它們作為一種特殊的“根”使用,從這裡展開對.class文件的搜索。從那個根開始,解釋器會尋找包名,並將每個點號(句點)替換成一個斜槓,從而生成從CLASSPATH根開始的一個路徑名(所以package foo.bar.baz會變成foo\bar\baz或者foo/bar/baz;具體是正斜槓還是反斜槓由操作系統決定)。隨後將它們連接到一起,成為CLASSPATH內的各個條目(入口)。以後搜索.class文件時,就可從這些地方開始查找與准備創建的類名對應的名字。此外,它也會搜索一些標准目錄——這些目錄與Java解釋器駐留的地方有關。
為進一步理解這個問題,下面以我自己的域名為例,它是bruceeckel.com。將其反轉過來後,com.bruceeckel就為我的類創建了獨一無二的全局名稱(com,edu,org,net等擴展名以前在Java包中都是大寫的,但自Java 1.2以來,這種情況已發生了變化。現在整個包名都是小寫的)。由於決定創建一個名為util的庫,我可以進一步地分割它,所以最後得到的包名如下:
package com.bruceeckel.util;
現在,可將這個包名作為下述兩個文件的“命名空間”使用:

 

//: Vector.java
// Creating a package
package com.bruceeckel.util;

public class Vector {
  public Vector() {
    System.out.println(
      "com.bruceeckel.util.Vector");
  }
} ///:~

創建自己的包時,要求package語句必須是文件中的第一個“非注釋”代碼。第二個文件表面看起來是類似的:

 

//: List.java
// Creating a package 
package com.bruceeckel.util;

public class List {
  public List() {
    System.out.println(
      "com.bruceeckel.util.List");
  }
} ///:~

這兩個文件都置於我自己系統的一個子目錄中:
C:\DOC\JavaT\com\bruceeckel\util
若通過它往回走,就會發現包名com.bruceeckel.util,但路徑的第一部分又是什麼呢?這是由CLASSPATH環境變量決定的。在我的機器上,它是:
CLASSPATH=.;D:\JAVA\LIB;C:\DOC\JavaT
可以看出,CLASSPATH裡能包含大量備用的搜索路徑。然而,使用JAR文件時要注意一個問題:必須將JAR文件的名字置於類路徑裡,而不僅僅是它所在的路徑。所以對一個名為grape.jar的JAR文件來說,我們的類路徑需要包括:
CLASSPATH=.;D:\JAVA\LIB;C:\flavors\grape.jar
正確設置好類路徑後,可將下面這個文件置於任何目錄裡(若在執行該程序時遇到麻煩,請參見第3章的3.1.2小節“賦值”):

 

//: LibTest.java
// Uses the library
package c05;
import com.bruceeckel.util.*;

public class LibTest {
  public static void main(String[] args) {
    Vector v = new Vector();
    List l = new List();
  }
} ///:~

編譯器遇到import語句後,它會搜索由CLASSPATH指定的目錄,查找子目錄com\bruceeckel\util,然後查找名稱適當的已編譯文件(對於Vector是Vector.class,對於List則是List.class)。注意Vector和List內無論類還是需要的方法都必須設為public。

1. 自動編譯
為導入的類首次創建一個對象時(或者訪問一個類的static成員時),編譯器會在適當的目錄裡尋找同名的.class文件(所以如果創建類X的一個對象,就應該是X.class)。若只發現X.class,它就是必須使用的那一個類。然而,如果它在相同的目錄中還發現了一個X.java,編譯器就會比較兩個文件的日期標記。如果X.java比X.class新,就會自動編譯X.java,生成一個最新的X.class。
對於一個特定的類,或在與它同名的.java文件中沒有找到它,就會對那個類采取上述的處理。

2. 沖突
若通過*導入了兩個庫,而且它們包括相同的名字,這時會出現什麼情況呢?例如,假定一個程序使用了下述導入語句:
import com.bruceeckel.util.*;
import java.util.*;
由於java.util.*也包含了一個Vector類,所以這會造成潛在的沖突。然而,只要沖突並不真的發生,那麼就不會產生任何問題——這當然是最理想的情況,因為否則的話,就需要進行大量編程工作,防范那些可能可能永遠也不會發生的沖突。
如現在試著生成一個Vector,就肯定會發生沖突。如下所示:
Vector v = new Vector();
它引用的到底是哪個Vector類呢?編譯器對這個問題沒有答案,讀者也不可能知道。所以編譯器會報告一個錯誤,強迫我們進行明確的說明。例如,假設我想使用標准的Java Vector,那麼必須象下面這樣編程:
java.util.Vector v = new java.util.Vector();
由於它(與CLASSPATH一起)完整指定了那個Vector的位置,所以不再需要import java.util.*語句,除非還想使用來自java.util的其他東西。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved