enum.values_占用内存的Enum.values()方法
enum.values
我是Java 枚舉的忠實擁護者 。 似乎我們一直在等待獲得它,但是當我們最終獲得它( J2SE 5 )時,該枚舉比C和C ++提供的枚舉要好得多,對我來說似乎“ 值得等待” 。 與Java enum一樣好,它也不是沒有問題。 特別是,Java枚舉的方法values()返回數組的新副本,該副本表示每次調用該數組時可能的值。
Java語言規范闡明了枚舉行為。 在Java語言規范Java SE 10 Edition中 , 第8.9節涵蓋了枚舉。 第8.9.3節 (“枚舉成員”)列出了兩個“隱式聲明的方法”: public static E[] values()和public static E valueOf(String name) 。 例8.9.3-1 (“使用增強的for循環遍歷枚舉常量”)演示了如何調用Enum.values()遍歷枚舉。 但是,問題在于Enum.values()返回一個數組,而Java中的數組是可變的[Java語言規范的10.9節 (“字符數組不是字符串”)提醒我們在區分Java時要注意這一點。 string和Java字符數組。]。 Java枚舉是緊密不變的,因此有意義的是,每次調用該枚舉以確保不更改與該枚舉關聯的數組時,該枚舉必須返回由values()方法返回的數組的克隆。
最近在OpenJDK 編譯器-開發郵件列表上的標題為“ 關于Enum.values()內存分配 ”的Enum.values()指出,當在緊密循環中調用Enum.values()克隆常量值數組時,它將分配大量內存。 ” 該消息的發布者補充說,這“可能是出于不變性”,并指出:“我能理解?!?該消息還引用了同一郵件列表上的2012年3月消息和相關主題。
編譯器-開發郵件列表上的兩個線程包括一些有趣的當前可用的解決方法。
- 將由values()返回的枚舉值數組緩存為元素的private static final數組,這些元素的初始private static final數組初始化為values()返回的數組。
- 緩存枚舉值的固定List 。
- 創建一個枚舉值的EnumSet 。
Brian Goetz在該線程上的消息開頭是“這本質上是API設計錯誤; 因為values()返回一個數組,并且數組是可變的,所以每次都必須復制該數組?!?[Goetz在該消息中還嘲笑了“ 凍結數組 ”(使Java數組變得不可變)的概念。]
這個問題不是新問題。 威廉·希爾茲(William Shields)在2009年12月發表的文章《 Java中的可變性,數組和臨時對象的成本 》指出:“所有這些的最大問題是Java數組是可變的?!?在撰寫有關Enum.values()提出的特定問題之前,Shields解釋了Java Date類中可變性的古老而眾所周知的問題:
Java枚舉有一個稱為values()的靜態方法,該方法返回該enum的所有實例的數組 。 在Date類的課程中,這個特殊的決定令人震驚。 List本來是更明智的選擇。 在內部,這意味著實例數組每次調用時都必須進行防御性復制...
對此問題的其他引用包括“ Enums.values()方法 ”(Guava線程)和“ Java的Enum.values()隱藏分配 ”(顯示緩存Enum.values()返回的數組)。 上面還寫了一個JDK錯誤: JDK-8073381 (“需要API來獲取枚舉值而不創建新數組”)。
下一個代碼清單中說明了本文中討論的一些當前可用的變通方法,這是一個簡單的Fruit枚舉,演示了以三種不同格式緩存該枚舉的值。
具有三個“值”的緩存集的Fruit.java枚舉
package dustin.examples.enums;import java.util.EnumSet; import java.util.List;/*** Fruit enum that demonstrates some currently available* approaches for caching an enum's values so that a new* copy of those values does not need to be instantiated* each time .values() is called.*/ public enum Fruit {APPLE("Apple"),APRICOT("Apricot"),BANANA("Banana"),BLACKBERRY("Blackberry"),BLUEBERRY("Blueberry"),BOYSENBERRY("Boysenberry"),CANTALOUPE("Cantaloupe"),CHERRY("Cherry"),CRANBERRY("Cranberry"),GRAPE("Grape"),GRAPEFRUIT("Grapefruit"),GUAVA("Guava"),HONEYDEW("Honeydew"),KIWI("Kiwi"),KUMQUAT("Kumquat"),LEMON("Lemon"),LIME("Lime"),MANGO("Mango"),ORANGE("Orange"),PAPAYA("Papaya"),PEACH("Peach"),PEAR("Pear"),PLUM("Plum"),RASPBERRY("Raspberry"),STRAWBERRY("Strawberry"),TANGERINE("Tangerine"),WATERMELON("Watermelon");private String fruitName;Fruit(final String newFruitName){fruitName = newFruitName;}/** Cached fruits in immutable list. */private static final List<Fruit> cachedFruitsList = List.of(Fruit.values());/** Cached fruits in EnumSet. */private static final EnumSet<Fruit> cachedFruitsEnumSet = EnumSet.allOf(Fruit.class);/** Cached fruits in original array form. */private static final Fruit[] cachedFruits = Fruit.values();public static List<Fruit> cachedListValues(){return cachedFruitsList;}public static EnumSet<Fruit> cachedEnumSetValues(){return cachedFruitsEnumSet;}public static Fruit[] cachedArrayValues(){return cachedFruits;} }在許多情況下,每次調用Enum.values()必須克隆其數組的事實實際上并不重要。 也就是說,不難設想在“緊縮循環”中反復調用Enum.values()會很有用,然后每次將枚舉值復制到數組中都會開始對內存產生明顯影響的情況并不難使用以及與更大內存使用相關的問題。 最好有一種標準的方法來以更有效的內存方式訪問枚舉的值。 前面提到的兩個線程討論了一些潛在實現此功能的想法。
翻譯自: https://www.javacodegeeks.com/2018/08/memory-hogging-enum-values-method.html
enum.values
總結
以上是生活随笔為你收集整理的enum.values_占用内存的Enum.values()方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博主:很可能A17 Pro就是苹果的骁龙
- 下一篇: 使用Spring Boot和H2可以正常