java默认代码地址_Java 8默认方法可能会破坏您的(用户)代码
java默認代碼地址
乍一看, 默認方法為Java虛擬機的指令集帶來了一個很棒的新功能。 最后,庫開發人員能夠開發已建立的API,而不會對其用戶代碼造成不兼容性。 使用默認方法,當將新方法引入該接口時,任何實現庫接口的用戶類都會自動采用默認代碼。 而且,一旦用戶更新了自己的實現類,他就可以使用對他的特定用例更有意義的東西來覆蓋默認值。 更好的是,用戶可以從重寫的方法中調用接口的默認實現,并在其周圍添加邏輯。
到目前為止,一切都很好。 但是,將默認方法添加到已建立的接口會使Java代碼無法編譯。 在查看示例時,這是最容易理解的。 讓我們假設一個庫需要其接口之一的類作為輸入:
interface SimpleInput {void foo();void bar(); }abstract class SimpleInputAdapter implements SimpleInput {@Overridepublic void bar() {// some default behavior ...} }在Java 8之前,接口和相應適配器類的上述組合是Java編程語言中相當普遍的模式。 圖書館供應商通常會提供適配器,以節省圖書館用戶的鍵入時間。 但是,還額外提供了接口,以允許近似多重繼承。
讓我們進一步假設用戶使用了此適配器:
class MyInput extends SimpleInputAdapter{@Overridepublic void foo() {// do something ...}@Overridepublic void bar() {super.bar();// do something additionally ...} }通過此實現,用戶最終可以與庫進行交互。 請注意,該實現如何覆蓋bar方法以向默認實現添加一些功能。
那么,如果庫遷移到Java 8,會發生什么呢? 首先,該庫很可能會棄用適配器類,并將功能移至默認方法。 結果,該接口現在將如下所示:
interface SimpleInput {void foo();default void bar() {// some default behavior} }使用此新界面,用戶可以更新其代碼以適應默認方法,而不必使用適配器類。 使用接口而不是適配器類的最大好處是能夠擴展除特定適配器之外的其他類。 讓我們付諸實踐,并遷移MyInput類以使用默認方法。 因為我們現在可以擴展另一個類,所以讓我們另外擴展一些第三方基類。 這個基類的作用在這里并不特別相關,因此讓我們假設這對我們的用例有意義。
class MyInput extends ThirdPartyBaseClass implements SimpleInput {@Overridepublic void foo() {// do something ...}@Overridepublic void bar() {SimpleInput.super.foo();// do something additionally ... } }為了實現與原始類中類似的行為,我們利用Java 8的新語法來調用特定接口的默認方法。 同樣,我們將myMethod的邏輯移到了一些基類MyBase 。 拍拍我們的肩膀。 很好的重構!
我們正在使用的庫取得了巨大的成功。 但是,維護人員需要添加另一個接口以提供更多功能。 此接口表示一個CompexInput ,它使用其他方法擴展了SimpleInput 。 因為默認方法通常被認為可以安全添加 ,所以維護者還重寫了SimpleInput的默認方法,并添加了一些行為以提供更好的默認值。 畢竟,在實現適配器類時,這樣做很普遍:
interface ComplexInput extends SimpleInput {void qux();@Overridedefault void bar() {SimpleInput.super.bar(); // so complex, we need to do more ...} }這項新功能非常強大,以至ThirdPartyBaseClass的維護者決定也依賴此庫。 為此,他為ThirdPartyLibrary實現了ComplexInput接口。
但這對MyInput類意味著什么? 由于通過擴展ThirdPartyBaseClass隱式實現ComplexInput ,調用SimpleInput的默認方法突然變得非法。 結果,用戶的代碼不再編譯。 另外,現在通常禁止調用此方法,因為Java認為此調用與調用間接超類的super-super方法一樣是非法的。 相反,您可以調用
ComplexInput類。 但是,這需要您首先在MyInput顯式實現此接口。 對于圖書館的用戶來說,這種變化很有可能是出乎意料的!
奇怪的是,Java運行時并沒有區別。 JVM的驗證程序將允許已編譯的類調用SimpleInput::foo即使已加載的類在運行時通過擴展ThirdPartyBaseClass的更新版本隱式實現了ComplexClass 。 這里只有編譯器抱怨。
但是我們從中學到什么呢? 簡而言之,請確保不要在另一個接口中覆蓋默認方法。 既不使用其他默認方法,也不使用抽象方法。 通常,請小心使用默認方法。 它們可以像Java的collection接口一樣輕松地簡化已建立的API的演變,但它們本身卻很復雜,因為它們允許執行類型層次結構中的方法調用。 在Java 7之前,您只需要通過遍歷線性類層次結構來查找實際調用的代碼。 僅當您確實覺得有必要時才添加這種復雜性。
翻譯自: https://www.javacodegeeks.com/2014/05/java-8-default-methods-can-break-your-users-code.html
java默認代碼地址
總結
以上是生活随笔為你收集整理的java默认代码地址_Java 8默认方法可能会破坏您的(用户)代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zip解压linux命令(zip解压 l
- 下一篇: Apache Camel 3 –骆驼核心