您好,登錄后才能下訂單哦!
今天小編給大家分享一下Java缺失的特性擴展方法是什么的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
擴展方法,就是能夠向現有類型直接“添加”方法,而無需創建新的派生類型、重新編譯或以其他方式修改現有類型。調用擴展方法的時候,與調用在類型中實際定義的方法相比沒有明顯的差異。
為什么需要擴展方法
考慮要實現這樣的功能:從 Redis 取出包含多個商品ID的字符串后(每個商品ID使用英文逗號分隔),先對商品ID進行去重(并能夠維持元素的順序),最后再使用英文逗號將各個商品ID進行連接。
假設在 Java 中能實現擴展方法,并且我們為數組添加了擴展方法 toList(將數組變為 List),為 List 添加了擴展方法 toSet(將 List 變為 LinkedHashSet),為 Collection 添加了擴展方法 join(將集合中元素的字符串形式使用給定的連接符進行連接),那我們將可以這樣寫代碼:
相信此刻你已經有了為什么需要擴展方法的答案:
可以對現有的類庫,進行直接增強,而不是使用工具類
相比使用工具類,使用類型本身的方法寫代碼更流暢更舒適
代碼更容易閱讀,因為是鏈式調用,而不是用靜態方法套娃
我們先來問問最近大火的 ChatGPT:
好吧,ChatGPT 認為 Java 里面的擴展方法就是通過工具類提供的靜態方法 :)。所以接下來我將介紹一種全新的黑科技:
Manifold
Manifold 的原理和 Lombok 是類似的,也是在編譯期間通過注解處理器進行處理。所以要在 IDEA 中正確使用 Manifold,需要安裝 Manifold IDEA 的插件:
然后再在項目 pom 的 maven-compiler-plugin 中加入 annotationProcessorPaths:
如果你的項目中使用了 Lombok,需要把 Lombok 也加入 annotationProcessorPaths:
JDK 中,String 的 split 方法,使用的是字符串作為參數,即 String[] split(String)。我們現在來為 String 添加一個擴展方法 String[] split(char):按給定的字符進行分割。
基于 Manifold,編寫擴展方法:
可以發現本質上還是工具類的靜態方法,但是有一些要求:
工具類需要使用 Manifold 的 @Extension 注解
靜態方法中,目標類型的參數,需要使用 @This 注解
工具類所在的包名,需要以 extensions.目標類型全限定類名 結尾
—— 用過 C# 的同學應該會會心一笑,這就是模仿的 C# 的擴展方法。
關于第 3 點,之所以有這個要求,是因為 Manifold 希望能快速找到項目中的擴展方法,避免對項目中所有的類進行注解掃描,提升處理的效率。
具備了擴展方法的能力,現在我們就可以這樣調用了:
Amazing!而且你可以發現,System.out.println(numStrs.toString()) 打印的居然是數組對象的字符串形式 —— 而不是數組對象的地址。查看反編譯后的 App.class,發現是將擴展方法的調用,替換為靜態方法調用:
而數組的 toString 方法,使用的是 Manifold 為數組定義的擴展方法 ManArrayExt.toString(@This Object array):
[Ljava.lang.String;@511d50c0 什么的,Goodbye,再也不見~
因為是在編譯期將擴展方法的調用替換為靜態方法調用,所以使用 Manifold 的擴展方法,即使調用方法的對象是 null 也沒有問題,因為處理后的代碼是把 null 作為參數傳遞到對應的靜態方法。比如我們對 Collection 進行擴展:
然后調用的時候:
java.lang.NullPointerException,Goodbye,再也不見~
我們看到 List<@Self(true) Object> 這樣的寫法:@Self 是用來表示被注解的值應該是什么類型,如果是 @Self,即 @Self(false),表示被注解的值和 @This 注解的值是同一個類型;@Self(true) 則表示是數組中元素的類型。
對于對象數組,我們可以看到 toList 方法返回的就是對應的 List(T 為數組元素的類型):
但如果是原始類型數組,IDEA 指示的返回值是:
但是我用的是 Java 啊,擦除法泛型怎么可能擁有 List 這么偉大的功能 —— 所以你只能用原生類型來接收這個返回值 :)
—— 許個愿,希望 Project Valhalla 早日 GA。
我們經常在各個項目中看到,大家先把某個對象包裝成 Optional,然后進行 filter、map 等。通過 @Self 的類型映射,你可以這樣為 Object 加入一個非常實用的辦法:
那么任何對象,都將擁有 asOpt() 方法。
相比于之前的需要包裝一下的不自然:
你現在可以自然而然的使用 Optional:
當然,Object 是所有的類的父類,這樣做是否合適,還是需要謹慎的思考一下。
我們都知道 Java9 給集合添加了工廠方法:
是不是很眼饞?因為如果用的不是 Java9 及以上版本(Java8:直接報我身份證就行),你就得用 Guava 之類的庫 —— 然而 ImmutableList.of 用起來終究是比不上 List.of 這樣的正統來的自然。
沒關系,Manifold 說:“無所謂,我會出手”。基于 Manifold 擴展靜態方法,就是在擴展類的靜態方法上,也加上 @Extension:
然后你就可以欺騙自己已經用上了 Java8 之后的版本 —— 你發任你發,我用 Java8。
BTW,因為 Object 是所有類的父類,如果你給 Object 添加靜態擴展方法,那么意味著你可以在任何地方直接訪問到這個靜態方法,而不需要 import —— 恭喜你,解鎖了 “頂級函數”。
以上就是“Java缺失的特性擴展方法是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。