2011年7月14日 星期四

java版本的向下相容

jre是向下相容的!
這向下相容有兩個面向

1.低版本編譯好的class, 能在高版本直接執行:
你以1.4版編譯好的class
能在1.6版的jre上直接執行, 不需做任何修改
換句話說
所以1.6版的jre能夠直接地
吃下比它低版本的class

2.高版本編譯好的class, 能在低版本執行:
咦?
這樣有下向相容嗎?
在1.6的jdk直接編譯: javac hello.java
這樣你拿去1.4版jre執行
會得到以下結果:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 50.0)

(拿高版本jdk編譯的java去低版本jre執行->當然不行, 因為沒有向上相容這件事)

你必須要加上兩個參數:-source和-target
-source: 要用java幾版, 來檢查程式內容, 是否合乎java文法
-target: 於前項檢查文法ok後, 編譯後產生的class檔將以何種java版本輸出

這裡要特別注意幾點:
a.-target的預設值 = -source的值
例如-source=1.4, 如果不加以設定-target
則此時-target=預設值=1.4
(但-source=1.2或1.3時, -target的值都等於1.4)

b.-target的值必須大於等於-source的值
比如-source=1.4
則-target可以等於1.5
若-target=1.3
執行javac後將會得到以下結果
javac: source release 1.4 requires target release 1.4

為-target做個實驗
用jdk 1.6寫一個簡單的java
執行:javac test.java
再拿到jre 1.4上去執行
結果是:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 50.0)
若執行的是:javac test.java -target 1.5
再拿到jre 1.4上去執行
結果是:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 49.0)
可以觀察到-target的值不同,
所產生出來的class檔的版本真的不一樣

這裡有個疑問
會有需要將-source和-target設定成不一樣的時候嗎
例如javac hello.java -source 1.4 -target  1.5

答案是, 需要視你要佈署的環境而定
舉個例子你本機是高版本的1.6
欲佈署在遠方的機器是低版本的1.5
然後你程式碼中有用到1.4才提供的功能
這個時候就相當適合使用:javac hello.java -source 1.4 -target  1.5

但記得前面我提過
高版本的jre能直接吃下低版本的class
所以, 結論是
你使用javac hello.java -source 1.4 -target  1.5最完美
但使用javac hello.java -source 1.4 -target  1.4也沒差, 是相同意思
可是使用javac hello.java -source 1.4 -target  1.3 <-錯誤!
因為-target的值必須大於等於-source的值

最後
提醒大家
雖然
高版本的jre能直接吃下低版本的class
但是程式總有需要修改的時候
所以在修改以前的程式後
有必要重新編譯時
必須要注要你所使用的 -source值

請看下面兩張圖, 分別是j2se1.4和j2se 5的api
其中String這個類別的api
圖一 j2se1.4的String API
圖二 j2se1.5的String API

可以注意到從1.4跨到1.5之後
本來在1.4中的方法compareTo(Object o)
已經消失了....也就是1.5把這個方法取消

可以寫個簡單類別來測試:
public class test{
 public static void main(String[] args){
  String a = "p";
  Object b = new String("p");
  if(a.compareTo(b)==0){
   System.out.println("They are equal!");
  }
 }
}

執行指令如下,
可以看到用-source 1.4編譯沒有錯誤
若用-source 1.5就會說你應該參數用String而不是Object
參照圖二, 就可以知道這是因為, j2se 1.5中已刪除 compareTo(Object o)的關係

C:\jpractice>javac test.java -source 1.4
C:\jpractice>javac test.java -source 1.5
test.java:5: compareTo(java.lang.String) in java.lang.String cannot be applied t
o (java.lang.Object)
                if(a.compareTo(b)==0){
                    ^
1 error
C:\jpractice>

編譯的時候
要注意使用哪個版本的java來檢查程式文法
但是只要一編譯好
以上例而言
以javac test.java -source 1.4編譯完成
拿到jre 1.6去執行時
雖然test.java裡使用了1.4版才有的String.compareTo()功能
但是因為高版本的jre能直接吃下低版本的class
所以能執行執行沒有問題
只不過編譯時要比較麻煩
加個-source參數
當然你應該不會想替專案裡的少數幾支java特別加上-source參數
專案裡所有的程式應該都是以同樣版本的java去編譯的
這樣才好維護
所以有發現有使用到已被高版本取消的方法時
還是趁早修改比較理想

沒有留言:

張貼留言