1. 程式人生 > >Java的package和import機制

Java的package和import機制

一些人用了一陣子的Java,可是對於 Java 的 package 跟 import 還是不太瞭解。很多人以為原始碼 .java 檔案中的 import 會讓編譯器把所 import 的程式通通寫到編譯好的 .class 檔案中,或是認為 import 跟 C/C++ 的 #include 相似,實際上,這是錯誤的觀念。

  讓我們先了解一下,Java 的 package 到底有何用處。

  其實,package 名稱就像是我們的姓,而 class 名稱就像是我們的名字。package 名稱有很多 . 的,就好像是複姓。比如說 java.lang.String,就是複姓 java.lang,名字為 String 的類別;java.io.InputStream 則是複姓java.io,名字為 InputStream 的類別。

  Java 會使用 package 這種機制的原因也非常明顯,就像我們取姓名一樣,光是一間學校的同一屆同學中,就有可能會出現不少同名的同學,如果不取姓的話,那學校在處理學生資料,或是同學彼此之間的稱呼,就會發生很大的困擾。相同的,全世界的 Java 類別數量,恐怕比臺灣人口還多,而且還不斷的在成長當中,如果類別不使用套件名稱,那在用到相同名稱的不同類別時,就會產生極大的困擾。幸運的是,Java 的套件名稱我們可以自己取,不像人的姓沒有太大的選擇 ( 所以有很多同名同姓的 ),如果依照 Sun 的規範來取套件名稱,那理論上不同人所取的套件名稱不會相同 ( 請參閱 "命名慣例"的相關文章 ),也就不會發生名稱衝突的情況。

  可是問題來了,因為很多套件的名稱非常的長,在寫程式時,會多打好多字,花費不少時間,比如說在A.B.C檔案下有Point和Circle兩個類,現在在程式中要呼叫:

     A.B.C.Point  P1=new A.B.C.Point();

     A.B.C.Circle  C1=new A.B.C.Circle();

實在是不美觀又麻煩.於是,Sun 想了一個辦法,就是 import. 就是在程式一開頭的時候,說明程式中會用到那些類的路徑.首先,在檔案開頭寫:

     import A.B.C.Point;

     import A.B.C.Circle;

這兩行說明了類的路徑,所以當程式中提到Point就是指A.B.C.Point,而Circle就是指A.B.C.Circle,依此類推。於是原來的程式就變成:

     Point  P1=new Point();

     Circle  C1=new Circle();  

這樣看起來是不是清爽多了呢?如果這些類別用的次數很多,那就更能體會到import 的好處了。可是這樣還是不夠,因為懶是人的天性,還是會有人覺得打太多 import 了也很浪費時間,於是 Sun 又提供了一個方法:

    import A.B.C.*; 意思就是,等一下程式中提到的沒有姓名的類別,全都包含在A.B.C這個目錄中。

  注意點:但我們在程式中經常使用System.out這個類,為什麼沒有import System.out呢,因為java.lang 這個套件實在是太常太常太常用到了,幾乎沒有程式不用它的,所以不管你有沒有寫 import java.lang;,編譯器都會自動幫你補上,也就是說編譯器只要看到沒有姓的類別,它就會自動去 java.lang 裡面找找看,看這個類別是不是屬於這個套件的。所以我們就不用特別去import java.lang 了。

   為甚麼我一開始說 import 跟 #include 不同呢?因為 import 的功能到此為止,它不像 #include 一樣,會將檔案內容載入進來。import 只是請編譯器幫你打字,讓編譯器把沒有姓的類別加上姓,並不會把別的檔案的程式碼寫進來。如果你想練習打字,可以不要使用 import,只要在用到類別的時候,用它的全部姓名來稱呼它就行了(就像例子一開始那樣),跟使用 import 完全沒有甚麼兩樣。

 

                                 先介紹Java的Package機制

基本原則:需要將類檔案切實安置到其所歸屬之Package所對應的相對路徑下。

例如:以下面程式為例:假設此Hello.java檔案在D:\Java\下
package  A;
public class Hello{
  public static void main(String args[]){   
     System.out.println("Hello World!");
  }
}

D:\Java>javac  Hello.java  此程式可以編譯通過.接著執行。
D:\Java>java  Hello       但是執行時,卻提示以下錯誤!
Exception in thread "main" java.lang.NoClassDefFoundError: hello (wrong name: A/Hello)
        at java.lang.ClassLoader.defineClass0(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:537)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:123)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:55)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:187)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:289)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:274)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:235)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)

原因是我們把生成的Hello.class規定打包在D:\Java\A檔案中,必須在A檔案中才能去執行。所以應該在D:\Java目錄下建立一個A目錄,然後把把Hello.class放在它下面,執行時,可正常通過!
D:\Java\>java A.hello   就會輸出:Hello world!

 

                              現在介紹Java的import機制

我們在D:\Java目錄下建立一個JInTian.java檔案,其內容如下:
import  A.Hello;
public class JInTian{
   public static void main(String[] args){
       Hello  Hello1=new Hello();
     }
}

D:\Java\>javac JInTian.java   編譯成功!

D:\Java\>java  JInTian      執行成功!

也就是你在JInTian.class中成功的引用了Hello.class這個類,是通過import A.Hello來實現的,如果你沒有這句話,就會提示不能找到Hello這個類。

提示1:如果你在D:\Java目錄下仍保留一個Hello.java檔案的話,執行對主程式的編譯命令時仍會報錯!你自己可以試試呀!
提示2:如果你刪除D:\Java\A\Hello.java檔案的話,只留Hello.class檔案,執行對主程式的編譯命令時是可以通過,此時可以不需要子程式的原始碼。
提出一個問題:如果把目錄A剪下到其它目錄,如D盤根目錄下,在A目錄如果執行編譯和執行命令呢?
很明顯,會報以下錯誤!當然了,前提條件是你沒有設定classpath路徑,其實只要沒把類搜尋路徑設定到我這個位置就會出錯的!你試試吧!

分類: 【4】【Java】