2011-12-25 50 views
1

我有一個我們寫的內部工具來爲我們的應用程序創建補丁。 它在scm中檢查哪些類已更改並使用javac進行編譯。
然後我們將創建的jar添加到類路徑中。 在過去,我們發現有一個問題: 如果我改變了A類中的方法返回類型,並且B類使用了那個方法,那麼A類簽名改變了,當B類調用該方法時,我們得到NoSuchMethodError
但是,現在我有一個不同的情況,類靜態變量發生了變化,我得到: java.lang.NoClassDefFoundError: Could not initialize class
你知道這是什麼原因嗎?
有沒有什麼辦法可以告訴我們在更改類時需要編譯哪些類?當班級改變時,我需要編譯哪些類?

+1

我想知道,如果它不會是更容易重新編譯一切,使用diff工具來查找實際更改的二進制文件。 – 2011-12-25 11:25:46

+0

我已閱讀了有關此問題的幾個詳細討論。簡單的答案是,知道需要重新編譯的東西並不簡單,並且沒有獨立的工具可以實現。 Eclipse增量式編譯器可以做到這一點,但只能作爲編譯的一部分。 @ JensSchauder的建議看起來很不錯。 – 2011-12-25 15:07:08

回答

4

這聽起來像是很多努力來開發我懷疑是不可靠的解決方案。

我會爲每個版本構建整個應用程序。要創建一個補丁,我會比較生成的類或文件與原始發行版中的類或文件。任何已更改的文件都將包含在內。

這是更好,因爲

  • 你不必瞭解不斷變化的一個常數,方法或類的所有後果。
  • 如果您更改偶然的格式或註釋等內容,則無需更新文件。
  • 你可以有信心,應用補丁是完全一樣的,並給予完整的分佈。
1

如果更改類A的簽名,則不必重新編譯調用此類的所有類。你必須改變這些類的實現。

例如,如果你的A類有方法foo()這是所謂的B類,現在你更名爲bar()你必須改變B類的源代碼,否則你會得到NoSuchMethodError

但是,如果您不改變接口但只是修改類A的內部實現,則不必重新編譯除此類之外的任何內容。編譯時只需創建適當的類路徑。類路徑必須包含類A的直接依賴關係和依賴關係的依賴關係。它不能包含第三級依賴關係(即依賴關係依賴關係的依賴關係)。但恕我直言,編譯補丁時處理類路徑的最簡單方法就是提供現有應用程序的完整類路徑。

+1

有些簽名更改可以簡單地重新編譯(至少有一些)用法,而無需更改任何源 - 例如,如果返回類型仍可分配給之前使用的相同類型,或者參數類型現在更寬。類似於常量的變化。 – 2011-12-25 11:34:16

3

此外,內聯public常量可能是難以定位的問題的來源,因爲它們不會導致異常或錯誤,但會導致沉默的錯誤行爲。

比方說你有一個類一個一些public static final字段是一個基本類型或一個String的,其值可以在編譯時確定。

public class A { 
    public static final String GREETING = "Hello"; 
    ... 
} 

然後,如果另一個類訪問該字段,編譯器內聯常數 - 即將A.GREETING參考替換爲其值"Hello"。沒有關於恆定值來自哪裏的信息。

現在到了麻煩 - 如果你改變GREETING價值可以說"Hi"並重新編譯只有類一個,直到你重新編譯過的類內聯值將保持不變。因此,像其他人已經指出的那樣,從零開始重建整個應用程序通常是一個更好的主意

一個很好的文章討論這個問題: http://marxsoftware.blogspot.com/2009/09/inconstant-constants-in-java.html

一些相關的SO問題:

Is Java guaranteed to inline string constants if they can be determined at compile time

Are all compile-time constants inlined?

相關問題