2008年10月30日 星期四

Java on Linux 簡易設定

01. 安裝環境
J2SE Development Kit 5.0 Update 16 with NetBeans IDE 6.1 Bundle
我所選擇的環境是Java SE 5.0 與Netbeans IDE 6.1的整合套件。JDK是一個開發的元件,內含java語言的編譯器、JVM,以及JRE(內有標準的類別函式庫)。也就是說一般的使用者只是想運行java程式,只要有JRE就好;如果想要開發java程式,則必須安裝JDK;如果想要一個圖形整合介面,那麼可以考慮昇陽官方的Netbeans。不過必須有一個觀念,Netbeans只是一個空殼,如果沒有JDK,Netbeans也只是一個圖形介面,什麼碗糕也跑不出來。因此如果不安裝bundle組合套件,那麼可以自己下載最新的JDK以及Netbeans IDE。

另一個應該注意的是,雖然安裝的JDK包含了JRE,不過當你在使用瀏覽器遇到使用java程式的時候,還是會出現警告找不到JRE的視窗。這是因為JDK會使用自帶的JRE,而這個JRE並不會給編譯java以外的事情使用,這是為了編譯時候的過程是順利、且可以確保版本號,因此JRE需要額外安裝。不過這樣所帶來的好處是,開發人員可以安裝多個JRE來測試不同環境所編譯出來的程式是否有任何異常問題,而系統預設以最高版本的JRE來運行。

02. 環境變數設定
首先,系統的shell並沒有辦法知道JDK在哪裡,你必須告知系統JRE的PATH,例如我放在/usr/local/jdk1.6.0_07/bin, 則應該在定義PATH的設定檔內修改成:

JAVA_HOME=/usr/local/jdk1.6.0_07
export PATH=$PATH:$JAVA_HOME/bin
除此之外,路徑對於JVM來說只是一個package。例如在unix上一個再普通不過的binary,你可以透過路徑的方式告知該做什麼動作:
gcc ../abc/test.c -o bin/test
不過java可不能這麼用。在當前目錄下假設有一個abc.java檔案(假設public類別名稱也為abc),詳細訊息可以這樣印出來:
javac -verbose abc.java
這個動作會產生abc.class的byte code:
java abc
來執行這隻程式。執行程式時,java會認為JVM才是真正的作業系統,以下是簡單的執行流程:
--class loader:指派記憶體位置。
--byte code verifier:進行雜湊校驗,比對是否真的由javac所原生。
--hotspot excution:就是JVM啦,有可能是client,也有可能是server。
--talk to hardware:由JVM產生native code與硬體溝通。

03. classpath與sourcepath的設定:
通常java會把編譯後的bytecode跟原始碼放在一起(而不是當前目錄)。不過,在執行一個大的project時,會撰寫成許多不同的類別,這時候為了除錯方便以及also compile方便,我們需要把source code與byte code分開。假設source codes放在src,而byte code放在classes,則我們在有abc.java的工作目錄時,編譯java需要這樣作:

javac -d classes -classpath PATH_OF_CLASS abc.java
-d:         告知java compiler編譯完成把byte code放在./classes裡。
-classpath  告知有哪些既有的class可用的路徑。效果等於-cp,但是-cp無法用於環境變數。
如果classes裡缺少某類別的byte code可以使用,則需要回頭編出一個class來使用。預設會在當前目錄找,但是如果找不到,則無法also compile--造成編譯失敗。解決的方法是指定sourcepath給java:
javac -d classes -sourcepath PATH_OF_SOURCE abc.java
-sourcepath 告知哪裡有.java原始檔。
假設在src下有多個套件,仍然只需要指定src即可,javac會自動往下找其他套件。
這樣java就知道去哪裡找cource code去編譯該類別出來。但是不建議sourcepath與classpath混用,因為混用的結果只有sourcepath有效(除非還有用到其他類別)。
javac -d classes -sourcepath PATH_OF_SOURCE -classpath PATH_OF_CLASS abc.java
理由是,當java compiler編譯時缺少某一類別,他會在sourcepath裡尋找是否有對應的.java。如果有,他也不會去找classpath,會直接再編譯一個byte code出來;因此在指定sourcepath以及classpath時,通常是不會同時使用的。javac會先抓取sourcepath引數,再抓取classpath引數。無論你是否先指定classpath,抓引數的順序仍然是先sourcepath再classpath。簡而言之:

利用-sourcepath達成also compile;
利用-classpath告知既存的類別檔位置。

當然,使用unix都是懶惰的人,總是希望事情可以簡化又依照我們的要求,我們可以把他寫進環境變數裡:
export CLASSPATH=~/java-workspace/classes
同樣的,如果要設定sourcepath,也寫成:
export SOURCEPATH=~/java-workspace/src
不過我實在很懶。如果每次編譯都要打這串javac -d classes,我實在覺得很煩。不過 -d存放class檔無法使用環境變數固定住,因此我目前想出來的方法是用alias。
alias javac='javac -d ~/java-workspace/classes'
問題就解決啦!如果是呆呆windows可能就沒這麼方便了。 為什麼要這麼麻煩去特別指定sourcepath以及classpath呢?假設今天有一個大專案,需要很多次修改某幾個類別,你一定不希望每個.java都被編譯一次,這時候可以「只」指定classpath,不指定sourcepath(在當前目錄),則系統就會去找既有的class來使用,降低了大量重複also compile的無謂cpu時間消耗。

04. 執行java
到此為止,編譯方面的環境設定就結束了;那麼執行呢?
傳統的程式編譯出來的binary,只要設定好PATH,則我們可以這樣作:

Testjava ../abcdef.txt
但是我已經設定好classpath了,因此我可以在任何一個地方下指令:
java Testjava
都可以順利執行。如果想要把Testjava變成外部命令,可以寫在alias:
alias Testjava='java Testjava'

關鍵字:java, java se, netbeans, classpath, sourcepath

沒有留言: