關於eclipse和javac編譯結果不一致的問題的分析與解決

問題:

下面一個簡單的類:

public class MyTest {
 private static String className = String.class.getName(); //紅色部分是下面問題的關鍵
 public static void main(String[] args){
  System.out.println(className);   
 }
}

經eclipse3.1.1編譯後(指定類兼容性版本爲1.4),再反編譯的結果是:

public class MyTest
{

    public MyTest()
    {
    }

    public static void main(String args[])
    {
        System.out.println(className);
    }

    private static String className;

    static
    {
        className = java.lang.String.class.getName();
    }
}

而經過sun javac(或者ant, antx)編譯後(JDK版本1.4,或者JDK1.5,但是編譯結果指定版本爲1.4),再反編譯的結果是:

public class MyTest
{

    public MyTest()
    {
    }

    public static void main(String args[])
    {
        System.out.println(className);
    }

    static Class _mthclass$(String x0)
    {
        return Class.forName(x0);
        ClassNotFoundException x1;
        x1;
        throw (new NoClassDefFoundError()).initCause(x1);
    }

    private static String className;

    static
    {
        className = (java.lang.String.class).getName();
    }
}

 

也就是說sun javac編譯出來的結果裏面多了一個_mthclass$方法,這個通常不會有什麼問題,不過在使用hot swap技術(例如Antx eclipse plugin中的快速部署插件利用hot swap來實現類的熱替換,或者某些類序列化的地方,這個就成爲問題了。

 

用_mthclass$在google上搜一把,結果不多,比較有價值的是這一篇:http://coding.derkeiler.com/Archive/Java/comp.lang.java.softwaretools/2004-01/0138.html

按照這個說法,這個問題是由於Sun本身沒有遵循規範,而eclipse compiler遵循規範導致的,而且eclipse compiler是沒有辦法替換的。

 

嘗試將JDK版本換成1.5,sun javac生成出來的_mthclass$是不見了,不過,這回奇怪的是eclipse的編譯結果中多了一個成員變量class$0,
下面是經eclipse3.1.1編譯後(指定類兼容性版本爲5.0),再反編譯的結果:
public class MyTest
{

    public MyTest()
    {
    }

    public static void main(String args[])
    {
        System.out.println(className);
    }

    private static String className = java/lang/String.getName();
    static Class class$0;

}
而經過sun javac(或者ant, antx)編譯後(JDK版本1.5),再反編譯的結果是:
public class MyTest
{

    public MyTest()
    {
    }

    public static void main(String args[])
    {
        System.out.println(className);
    }

    private static String className = java/lang/String.getName();

}

再在goole上搜了一把,發現了Eclipse3.2有兩個比較重要的特徵:
1.與javac的兼容性更好。
2.提供了單獨的編譯器,可以在eclipse外部使用,包括ant中使用。

於是下載eclipse3.2版本,首先驗證一下其與sun javac的兼容性如何,
使用JDK1.4版本的時候,還是老樣子,sun javac編譯出來的_mthclass$方法在eclipse3.2的編譯結果中還是不存在,所以還是不兼容的。
不過使用JDK1.5版本的時候,這會eclipse 3.2的編譯結果總算和sun javac一致了。

雖然,用JDK1.5加上eclipse 3.2已經保證了這個類在兩種編譯器下的兼容性,不過總覺得不踏實:
1.誰知道這兩個編譯器還有沒有其它不兼容的地方呢?
2.版本要求太嚴格,很多由於各種原因沒有使用這些版本的很麻煩。

因此,還是從根本上解決這個問題比較合適:根本上解決最好就是不要使用兩種不同的編譯器,而使用同一種。
由於eclipse環境下的編譯器是不可替換的,所以企圖都使用sun javac的方式不太可行,那麼統一使用eclipse自帶的編譯器如何呢?
剛纔提到的eclipse3.2的第二個比較重要的特性就派上用場了。
獨立的eclipse編譯器(1M大小而已)可以在如下地址下載:http://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops/R-3.2-200606291905/ecj.jar
這個獨立的編譯器在antx下的使用也很簡單:(關於該編譯器的獨立使用或者ant下面的使用可以參看this help section: JDT Plug-in Developer Guide>Programmer's Guide>JDT Core>Compiling Java code)
1.將下載下來的編譯器放在ANTX_HOME/lib目錄下面。
2.在總控項目文件的project.xml增加這麼一行即可:<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
這樣就保證了通過antx打包的類也是用eclipse的編譯器編譯出來的,當然就不應該存在類不兼容的情況了。

 

實際上,eclipse3.1.1版本也已經提供了獨立的eclipse編譯器,不過當時並沒有單獨提供獨立的包下載,如果希望使用3.1.1版本的eclipse編譯器,可以使用org.eclipse.jdt.core_3.1.1.jar以及其中包含的jdtCompilerAdapter.jar。(eclipse3.1.1環境的編譯器我沒有獨立驗證過)

發佈了39 篇原創文章 · 獲贊 6 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章