2008-09-16 34 views
10

我維護一個Java Swing應用程序。Java編譯 - 有沒有辦法告訴編譯器忽略我的部分代碼?

與Java 5(蘋果機)的向後兼容性,我們維持兩個代碼庫,1層從Java 6使用的功能,另一個沒有這些特徵。

除了3-4個使用Java 6功能的類以外,代碼基本相同。

我希望只維護1個代碼庫。在編譯期間,有沒有辦法讓Java 5編譯器'忽略'我的代碼的某些部分?

我不想簡單地評論/取消註釋我的代碼的一部分,這取決於我的java編譯器的版本。

回答

4

假設這些類與1.5和6.0的實現差異具有相似的功能,您可以將它們合併到一個類中。然後,在不編輯註釋/取消註釋的源代碼的情況下,您可以依靠編譯器始終執行的優化。如果if表達式始終爲false,則if語句中的代碼將不會包含在編譯中。

你可以做一個靜態變量在類中的一個來確定要運行哪個版本:

public static final boolean COMPILED_IN_JAVA_6 = false; 

,然後讓受影響的類檢查靜態變量,把代碼的不同部分在簡單如果語句

if (VersionUtil.COMPILED_IN_JAVA_6) { 
    // Java 6 stuff goes here 
} else { 
    // Java 1.5 stuff goes here 
} 

然後,當你想編譯另一個版本,你只需要改變一個變量並重新編譯。它可能會使java文件變大,但它會整合您的代碼並消除您擁有的任何代碼重複。您的編輯可能會抱怨無法訪問的代碼或其他任何內容,但編譯器應該會很樂意忽略它。

+0

這是Java編譯器的文檔化行爲嗎? – 2008-10-24 10:37:50

+3

這個答案似乎不正確。我做了一個使用java.io.Console和上述方法的快速Java應用程序。編譯器在1.5中失敗,出現如下錯誤: Test.java:8:找不到符號:方法console() location:class java.lang.System – noahlz 2009-01-30 19:54:39

4

我認爲這裏最好的方法可能是使用構建腳本。您可以將所有代碼放在一個位置,通過選擇要包含的文件以及不包含的文件,可以選擇要編譯的代碼版本。請注意,如果您需要比每個文件更細的控制,這可能無濟於事。

1

不是,但有解決方法。見 http://forums.sun.com/thread.jspa?threadID=154106&messageID=447625

這就是說,你應該至少具有Java 5中,一個文件的一個版本的Java 6通過構建棒,並且將其包括或作出適當的。把它全部放在一個大文件中,並試圖讓5編譯器忽略它不理解的東西不是一個好的解決方案。

HTH

- 尼克 -

1

這將使所有的Java較真畏縮(這是有趣的,嘿嘿),但我會使用C預處理,放的#ifdefs在我的源代碼。 makefile,rakefile或其他控制你的構建的東西,必須運行cpp來創建一個臨時文件來提供編譯器。我不知道螞蟻是否可以做到這一點。

雖然stackoverflow看起來像它將地方的所有答案,你可以wehn沒有人看到mosey對於智慧的http://www.javaranch.com。我想這個問題在很久以前就已經在那裏得到處理了。

0

Java中沒有預編譯器。因此,沒有辦法像C中那樣做#ifdef。 構建腳本將是最好的方法。

+0

他建議使用s C編譯器來運行實際的C預處理器,它將輸出修改後的源文件,然後在這些文件上運行Java編譯器。大部分(如果不是全部)C編譯器都只有一個開關來運行預處理器。 – 2008-09-16 16:37:29

0

您可以獲得條件編譯,但不是很好 - javac將忽略無法訪問的代碼。因此,如果你正確地構建你的代碼,你可以讓編譯器忽略你的代碼的一部分。爲了正確使用它,您還需要將正確的參數傳遞給javac,以便它不會將不可訪問的代碼報告爲錯誤,並拒絕編譯:-)

2

保留在JDK 5下構建的一個「主」源根。添加必須在JDK 6或更高版本下構建的第二個並行源根目錄。 (不應該有重疊,即兩個都不存在類)。使用一個接口來定義兩者之間的入口點以及一點反射。

例如:

---%<--- main/RandomClass.java 
// ... 
if (...is JDK 6+...) { 
    try { 
     JDK6Interface i = (JDK6Interface) 
      Class.forName("JDK6Impl").newInstance(); 
     i.browseDesktop(...); 
    } catch (Exception x) { 
     // fall back... 
    } 
} 
---%<--- main/JDK6Interface.java 
public interface JDK6Interface { 
    void browseDesktop(URI uri); 
} 
---%<--- jdk6/JDK6Impl.java 
public class JDK6Impl implements JDK6Interface { 
    public void browseDesktop(URI uri) { 
     java.awt.Desktop.getDesktop().browse(uri); 
    } 
} 
---%<--- 

你可以配置這些因採用不同的JDK在IDE中單獨的項目,等等。問題在於主根可以獨立編譯,並且非常清楚您可以在哪個根中使用哪些根目錄,而如果您嘗試單獨編譯單個根的不同部分,則很容易意外地「泄漏」JDK 6的使用進入錯誤的文件。您可以使用某種服務註冊系統 - java.util.ServiceLoader(如果main可以使用JDK 6,並且您希望可選支持JDK 7!),NetBeans Lookup, Spring等等。

同樣的技術可以用來創建對可選庫的支持,而不是新的JDK。

2

你可能可以重構你的代碼,這樣條件編譯確實不是必須的,只是有條件的類加載。像這樣:

public interface Opener{ 

public void open(File f); 

public static class Util{ 
     public Opener getOpener(){ 
      if(System.getProperty("java.version").beginsWith("1.5")){ 
      return new Java5Opener(); 
      } 
      try{ 
      return new Java6Opener(); 
      }catch(Throwable t){ 
      return new Java5Opener(); 
      } 
     } 
} 

} 

這可能是一個很大的努力,取決於你有多少版本特定的代碼段。

0

上面提到的公共靜態最終解決方案還有一個作者沒有提到的額外好處 - 據我瞭解,編譯器會在編譯時識別它,並編譯出if語句中的任何代碼,那最後的變數。

所以我認爲這是您尋找的確切解決方案。

0

一個簡單的解決辦法是:

  • 將您的正常類路徑之外的不同類別。
  • 編寫一個簡單的自定義類加載器並將其作爲默認安裝在main中。
  • 對於除5/6之外的所有類,cassloader都可以推遲到它的父類(正常系統類加載器)
  • 對於5/6的類(這應該是唯一不能由父類找到的類)它可以通過'os.name'屬性或你自己的屬性來決定使用哪一個。
1

這取決於您要使用的Java 6功能。對於像添加一行分揀機到JTable中一個簡單的事情,實際上你可以在運行時進行測試:

private static final double javaVersion = 
     Double.parseDouble(System.getProperty("java.version").substring(0, 3)); 
private static final boolean supportsRowSorter = 
     (javaVersion >= 1.6); 

//... 

if (supportsRowSorter) { 
    myTable.setAutoCreateRowSorter(true); 
} else { 
    // not supported 
} 

此代碼必須與Java 6編譯,但可以使用任何版本(沒有新的類引用)運行。

編輯:更正確的,它將與1.3以來的任何版本(根據this page)工作。

5

有關使用自定義類加載器和動態註釋的代碼的建議,在維護和維護任何可憐的靈魂拾起項目並在新的牧場後重新啓動時的完整性時,都有點不可思議。

該解決方案很簡單。將受影響的類拖放到兩個獨立的獨立項目中 - 確保包名稱相同,然後將其編譯爲可在主項目中使用的jar。如果保持軟件包名稱相同,並且方法簽名相同,則不會出現問題 - 只需將您需要的任何版本的jar放入您的部署腳本即可。我假設你運行單獨的構建腳本或在同一個腳本中有單獨的目標 - ant和maven都可以輕鬆處理有條件地抓取文件並複製它們。

1

您可以完全在Java6上編譯所有代碼,然後使用System.getProperty(「java.version」)有條件地運行Java5或Java6代碼路徑。

您可以在一個類中擁有僅包含Java6的代碼,只要Java6-only代碼路徑未執行,該類就可以在Java5上正常運行。

這是一個技巧,用於編寫將在古老的MSJVM上運行的applet,直到全新的Java Plug-in JVM。

0

您可以使用反射API。將所有1.5代碼放在一個類中,1.6 api放在另一個類中。在你的ant腳本中,爲1.5創建兩個目標,一個不能編譯1.6類,另一個1.6不能編譯1.5。在你的代碼中檢查你的Java版本並使用反射來加載適當的類,javac將不會抱怨缺少的函數。這就是我如何在Windows上編譯我的MRJ(Mac Runtime for Java)應用程序。

相關問題