使用 import 偷懶


使用套件管理,解決了實體檔案與撰寫程式時類別名稱衝突的問題,但若每次撰寫程式時,都得鍵入完全吻合名稱,卻也是件麻煩的事,想想看,有些套件定義的名稱很長時,單是要鍵入完全吻合名稱得花多少時間。


你可以用import偷懶一下,例如:

package cc.openhome;

import cc.openhome.util.Console;

public class Main {
    public static void main(String[] args) {
        Console.writeLine("Hello World");
    }
}

編譯與執行時的指令方式,與 使用 package 管理類別 中談過的相同。當編譯器剖析Main.java看到import宣告時,會先記得import的名稱,後續剖析程式時,若看到Console名稱,原本會不知道Console是什麼東西,但編譯器記得你用import告訴過它,如果遇到不認識的名稱,可以比對一下import過的名稱,編譯器試著使用cc.openhome.util.Console,結果可以在指定的類別路徑中,cc/openhome/util資料夾下找到Console.class,於是可以進行編譯。

所以import只是告訴編譯器,遇到不認識的類別名稱,可以嘗試使用import過的名稱,import讓你少打一些字,讓編譯器多為你作一些事。

如果同一套件下會使用到多個類別,你也許會多次使用import

import cc.openhome.Message;
import cc.openhome.User;
import cc.openhome.Address;

你可以更偷懶一些,用以下的import語句:

import cc.openhome.*;


先前程式也可以使用以下的import語句,而編譯與執行結果相同:

import cc.openhome.util.*;

當編譯器剖析Main.java看到import的宣告時,會先記得有cc.openhome.util套件名稱,在後續剖析到Console名稱時,發現它不認識Cosnole是什麼東西,但編譯器記得你用import告訴過它,若遇到不認識的名稱,可以比對一下import過的名稱,編譯器試著將cc.openhome.utilConsole結合為cc.openhome.util.Console,結果可以在指定的類別路徑中,cc/openhome/util資料夾下找到Console.class,於是可以進行編譯。

偷懶也是有個限度,如果你自己寫了一個Arrays

package cc.openhome;
public class Arrays {
    ...
}

若在某個類別中撰寫有以下的程式碼:

import cc.openhome.*;
import java.util.*;
public class Some {
    public static void main(String[] args) {
        Arrays arrays;
         ...
    }
}

那麼編譯時,你會發現有以下錯誤訊息:

C:\workspace\Hello1>javac -sourcepath src -cp classes -d classes src/Some.java
src\Some.java:6: error: reference to Arrays is ambiguous
            Arrays arrays;
            ^
  both class java.util.Arrays in java.util and class cc.openhome.Arrays in cc.op
enhome match
1 error


當編譯器剖析Some.java看到import的宣告時,會先記得有cc.openhome套件名稱,在繼續剖析至Arrays該行時,發現它不認識Arrays是什麼東西,但編譯器記得你用import告訴過他,若遇到不認識的名稱,可以比對import過的名稱,編譯器試著將cc.openhomeArrays結合在一起為cc.openhome.Arrays,結果可以在類別路徑中,cc/openhome資料夾下找到Arrays.class。

然而,編譯器試著將java.utilArrays結合在一起為java.util.Arrays,發現也可以在Java SE API的rt.jar中(預設的類別載入路徑之一),對應的java/util資料夾中找到Arrays.class,於是編譯器困惑了,到底該使用cc.openhome.Arrays還是java.util.Arrays

遇到這種情況時,就不能偷懶了,你要使用哪個類別名稱,就得明確地逐字打出來:

import cc.openhome.*;
import java.util.*;
public class Some {
    public static void main(String[] args) {
        cc.openhome.Arrays arrays;
         ...
    }
}

這個程式就可以通過編譯了。簡單地說,import是偷懶工具,不能偷懶就回歸最保守的寫法。

在Java SE API中有許多常用類別,像是寫第一個Java程式時使用的System類別,其實也有使用套件管理,完整名稱其實是java.lang.System,在java.lang套件下的類別由於很常用,不用撰寫import也可以直接使用class定義的名稱,這也就是為何不用如下撰寫程式的原因(寫了當然也沒關係,只是自找麻煩):

java.lang.System.out.println("Hello!World!");

如果類別位於同一套件,彼此使用並不需要import,當編譯器看到一個沒有套件管理的類別名稱,會先在同一套件中尋找類別,如果找到就使用,若沒找到,再試著從import陳述進行比對。java.lang可視為預設就有import,沒有寫任何import陳述時,也會試著比對java.lang的組合,看看是否能找到對應類別。

原始碼檔案或位元碼檔案,都可以使用JAR檔案封裝,在文字模式下,可以使用JDK的jar工具程式來製作JAR檔案,你可以參考 JAR 檔中的原始檔、類別檔