日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

扩展方法 枚举值_扩展枚举功能的两种方法

發(fā)布時(shí)間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 扩展方法 枚举值_扩展枚举功能的两种方法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

擴(kuò)展方法 枚舉值

前言

在上一篇文章中,我解釋了如何以及為什么在Java代碼中使用enums而不是switch/case控制結(jié)構(gòu)。 在這里,我將展示如何擴(kuò)展現(xiàn)有enums功能。

介紹

Java enum是一種編譯器魔術(shù)。 在字節(jié)碼中,任何enum都表示為擴(kuò)展抽象類java.lang.Enum并具有幾個(gè)靜態(tài)成員的類。 因此,枚舉不能擴(kuò)展任何其他類或枚舉:沒(méi)有多重繼承。

類也不能擴(kuò)展枚舉。 此限制由編譯器強(qiáng)制執(zhí)行。

這是一個(gè)簡(jiǎn)單的enum :

enum Color {red, green, blue}

此類嘗試擴(kuò)展它:

SubColor class extends Color {}

這是嘗試編譯類SubColor的結(jié)果:

$ javac SubColor.java SubColor.java: 1 : error: cannot inherit from final Color SubColor class extends Color {} ^ SubColor.java: 1 : error: enum types are not extensible SubColor class extends Color {} ^ 2 errors

Enum既不能擴(kuò)展也不能擴(kuò)展。 那么,如何擴(kuò)展其功能呢? 關(guān)鍵字是“功能”。 Enum可以實(shí)現(xiàn)方法。 例如,枚舉Color可以聲明抽象方法draw() ,每個(gè)成員都可以重寫(xiě)它:

enum Color {red { @Override public void draw() { } },green { @Override public void draw() { } },blue { @Override public void draw() { } },;public abstract void draw(); } 在此說(shuō)明該技術(shù)的流行用法。 不幸的是,不可能總是在枚舉本身中實(shí)現(xiàn)方法,因?yàn)?#xff1a;
  • 枚舉可能屬于第三方庫(kù)或公司中的其他團(tuán)隊(duì)
  • 枚舉可能被過(guò)多的其他數(shù)據(jù)和函數(shù)重載,因此變得不可讀
  • 枚舉屬于不具有實(shí)現(xiàn)方法draw()所需的依賴項(xiàng)的模塊。
  • 本文針對(duì)此問(wèn)題提出了以下解決方案。

    鏡像枚舉

    我們不能修改枚舉顏色嗎? 沒(méi)問(wèn)題! 讓我們創(chuàng)建具有與Color完全相同的元素的枚舉DrawableColor。 這個(gè)新的枚舉將實(shí)現(xiàn)我們的方法draw(): enum DrawableColor {red { @Override public void draw() { } },green { @Override public void draw() { } },blue { @Override public void draw() { } },;public abstract void draw(); }

    這個(gè)枚舉是源枚舉Color的一種反映,即Color是它的鏡像 。但是如何使用新的枚舉呢? 我們所有的代碼都使用Color ,而不是DrawableColor 。 實(shí)現(xiàn)此過(guò)渡的最簡(jiǎn)單方法是使用內(nèi)置的枚舉方法name()和valueOf(),如下所示:

    Color color = ... DrawableColor.valueOf(color.name()).draw();

    由于name()方法是最終方法,不能被覆蓋,并且valueOf()由編譯器生成,因此這些方法始終相互配合,因此在此不會(huì)出現(xiàn)功能問(wèn)題。 這種過(guò)渡的性能也很好:方法name()甚至不創(chuàng)建新的String而是返回預(yù)先初始化的字符串(請(qǐng)參見(jiàn)java.lang.Enum源代碼)。 方法valueOf()是使用Map實(shí)現(xiàn)的,因此其復(fù)雜度為O(1)。

    上面的代碼包含明顯的問(wèn)題。 如果更改了源枚舉Color,則輔助枚舉DrawableColor不知道這一事實(shí),因此使用name()和valueOf()的技巧在運(yùn)行時(shí)將失敗。 我們不希望這種情況發(fā)生。 但是如何防止可能的故障呢?

    我們必須讓DrawableColor知道它的鏡像是Color,并且最好在編譯時(shí)或至少在單元測(cè)試階段強(qiáng)制執(zhí)行它。 在這里,我們建議在單元測(cè)試執(zhí)行期間進(jìn)行驗(yàn)證。 Enum可以實(shí)現(xiàn)時(shí)所執(zhí)行的靜態(tài)初始化enum中的任何代碼被提及。 這實(shí)際上意味著,如果靜態(tài)初始化程序驗(yàn)證枚舉DrawableColor是否適合Color,則足以執(zhí)行以下測(cè)試,以確保代碼不會(huì)在生產(chǎn)環(huán)境中被破壞:

    @Test public void drawableColorFitsMirror {DrawableColor.values(); }

    靜態(tài)初始化程序只需要比較DrawableColor和Color元素,如果不匹配則拋出異常。 該代碼很簡(jiǎn)單,可以針對(duì)每種特殊情況編寫(xiě)。 幸運(yùn)的是,名為enumus的簡(jiǎn)單開(kāi)放源代碼庫(kù)已經(jīng)實(shí)現(xiàn)了此功能,因此該任務(wù)變得微不足道:

    enum DrawableColor {....static {Mirror.of(Color.class);} }

    而已。 如果源枚舉和DrawableColor不再合適,則測(cè)試將失敗。 實(shí)用程序類Mirror具有獲取2個(gè)參數(shù)的其他方法:必須適合2個(gè)枚舉的類。 可以從代碼中的任何位置調(diào)用此版本,而不僅僅是從必須經(jīng)過(guò)驗(yàn)證的枚舉中調(diào)用。

    枚舉地圖

    我們是否真的必須定義僅包含一種方法的實(shí)現(xiàn)的另一個(gè)枚舉? 實(shí)際上,我們不必這樣做。 這是一個(gè)替代解決方案。 讓我們定義接口抽屜如下:

    public interface Drawer {void draw(); }

    現(xiàn)在,讓我們?cè)诿杜e元素和接口Drawer的實(shí)現(xiàn)之間創(chuàng)建映射:

    Map<Color, Drawer> drawers = new EnumMap<>(Color.class) {{put(red, new Drawer() { @Override public void draw();});put(green, new Drawer() { @Override public void draw();})put(blue, new Drawer() { @Override public void draw();}) }}

    用法很簡(jiǎn)單:

    drawers.get(color).draw();

    這里選擇EnumMap作為Map實(shí)現(xiàn),以獲得更好的性能。 Map保證每個(gè)枚舉元素僅出現(xiàn)一次。 但是,它不能保證每個(gè)enum元素都有相應(yīng)的條目。 但是檢查映射的大小等于enum元素的數(shù)量就足夠了:

    drawers.size() == Color.values().length


    枚舉還建議在這種情況下方便實(shí)用。 如果地圖不適合Color,則以下代碼將引發(fā)IllegalStateException及其描述性消息:

    EnumMapValidator.validateValues(Color. class , map, "Colors map" );

    從單元測(cè)試執(zhí)行的代碼中調(diào)用驗(yàn)證器很重要。 在這種情況下,基于地圖的解決方案對(duì)于將來(lái)對(duì)源枚舉的修改是安全的。

    EnumMap和Java 8功能接口

    實(shí)際上,我們不必定義特殊的接口來(lái)擴(kuò)展
    枚舉功能。 從版本8開(kāi)始,我們可以使用JDK提供的功能接口之一( Function,BiFunction,Consumer,BiConsumer,
    Supplieretc Function,BiFunction,Consumer,BiConsumer,
    Supplieretc Function,BiFunction,Consumer,BiConsumer,
    Supplieretc 。)選擇取決于必須發(fā)送給功能的參數(shù)。 例如,可以使用Supplier代替上一個(gè)示例中定義的Drawable :

    Map<Color, Supplier<Void>> drawers = new EnumMap<>(Color. class ) {{ put(red, new Supplier<Void>() { @Override public void get();}); put(green, new Supplier<Void>() { @Override public void get();}) put(blue, new Supplier<Void>() { @Override public void get();}) }}


    該映射的用法與上一個(gè)示例非常相似:

    drawers.get(color).get();

    該地圖可以與存儲(chǔ)以下實(shí)例的地圖完全一樣地進(jìn)行驗(yàn)證:
    可繪制。

    結(jié)論

    本文說(shuō)明了如果我們?cè)谄渲刑砑右恍┻壿?#xff0c;那么Java enums有多么強(qiáng)大。 它還演示了兩種擴(kuò)展語(yǔ)言enums功能的方法,盡管存在語(yǔ)言限制。 本文向用戶介紹了名為enumus的開(kāi)源庫(kù),該庫(kù)提供了幾個(gè)有用的實(shí)用工具,這些工具有助于簡(jiǎn)化 enums操作。

    翻譯自: https://www.javacodegeeks.com/2019/03/two-ways-extend-enum-functionality.html

    擴(kuò)展方法 枚舉值

    總結(jié)

    以上是生活随笔為你收集整理的扩展方法 枚举值_扩展枚举功能的两种方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。