【问题标题】:What does EnumSet really mean?EnumSet 的真正含义是什么?
【发布时间】:2012-08-03 05:32:34
【问题描述】:

我有以下例子:

import java.util.EnumSet;
import java.util.Iterator;

public class SizeSet {

    public static void main(String[] args) {
        EnumSet largeSize = EnumSet.of(Size.XL,Size.XXL,Size.XXXL);
        for(Iterator it = largeSize.iterator();it.hasNext();){
            Size size = (Size)it.next();
            System.out.println(size);
        }
    }
}


enum Size {
  S, M, L, XL, XXL, XXXL;

}

在这段代码中,我可以理解 Enum 创建了一个 Enum 类型的 Sizes。

我的问题是:largeSize 是 EnumSet 类型的对象吗?它的真正含义是什么?我真的很想更好地理解它。

【问题讨论】:

    标签: java object enums enumset


    【解决方案1】:

    对于任何变量,它的类型都可以在其声明中找到:

    EnumSet largeSize
    

    所以是的,largeSize(应该命名为largeSizes,因为它是一个集合)是EnumSet 类型。它也应该被泛化,因此被声明为

    EnumSet<Size> largeSizes
    

    这意味着largeSizes 的类型是EnumSetEnumSet 是一个Set,它包含特定枚举类型的枚举实例,比其他Set 实现(如HashSetTreeSet 等)更有效。要了解EnumSet 是什么,请阅读其API

    【讨论】:

    • 所以它是一种 Enum 内的 Enum ?表示另一个对象 (largeSizes) 代表对象 (Sizes) 的一部分?
    • 不,它是一组枚举值。 largeSizes 是一个包含 XL、XXL 和 XXXL 的集合。您可以用 HashSet 替换它,除了性能和内存消耗之外,它不会改变任何东西。 Size 不是对象。这是一堂课。并且这个类定义了几个常量:Size类型的L、XL、XXL等。
    • 我没有很好理解...如果 Size(应该是 Sizes)是一个对象,为什么它看起来不像:Enum Sizes = new Enum; ?然后是第一个代码中的最后 3 行?如果我可以制作一个 Size 的“size”对象,则意味着 Size 应该是一个 Class....
    • Size 不应为 Sizes。 XL 是 Size,而不是 SizesSizeNOT 对象。这是一堂课。 Size.XLSize 类的 6 个实例之一。根据定义,枚举是仅具有固定数量实例的类(在本例中为 S、M、... XXXL)。您不能创建枚举的新实例,否则它将不再是枚举。 Size 一个类。所有枚举都是类,但以不同的方式定义。
    【解决方案2】:

    一个简单的Enum 是一个值列表,您一次只能从中选择一个。使用您的示例,对于任何给定的布料,尺寸只能是 S、M、L 等之一。您可以使用简单的常量代替Enum,但这具有可读性、易于维护和严格类型检查的优点。

    当您需要一个变量同时假设多个Enum 值时,将使用EnumSet。例如,您在屏幕上写入的字体可以同时是 bolditalicEnumSet 将允许您添加各种值并测试其中一个值是否在任何给定时间实际设置。如果您是从其他编程语言接触 Java 的,这就是通常称为 flags 的功能。

    比较两者:

    enum Size { S, M, L, XL, XXL, XXXL }
    Size currentSize;
    ...
    currentSize = Size.S;
    ...
    if (currentSize == Size.S) ...
    

    定义、分配然后检查单个 Enum 值。

    enum FontStyle { Bold, Italic, Underline, Strikethrough }
    EnumSet<FontStyle> currentStyle;
    ...
    currentStyle = EnumSet.of(FontStyle.Bold, FontStyle.Italic);
    ...
    if (currentStyle.contains(FontStyle.Italic)) ...
    

    同时定义、分配两个Enum 值,然后检查其中一个是否实际设置。

    【讨论】:

      【解决方案3】:

      简化您的代码

      EnumSet<Size> largeSize = EnumSet.of(Size.XXXL, Size.XXL, Size.XL, Size.L);
      for(Size size: largeSize)
          System.out.print(size+" ");
      

      您可以看到 largeSize 是一个常规 Set,除了它旨在存储 Enums 之外。那有什么不同?首先,JVM 知道集合的所有可能值,这意味着它可以使用位图代替存储所有对象,其中 1 表示项目存在,0 表示不存在。这也意味着集合的顺序是序数值的顺序,即它们被定义的顺序。这就是打印的原因

      L XL XXL XXXL
      

      如果您想了解更多详细信息,我建议您阅读该课程的源代码。

      【讨论】:

        【解决方案4】:

        来自 Joshua Bloch 的书本身和他自己的话:

        java.util 包提供了 EnumSet 类来高效地表示 从单个枚举类型中提取的值集。这个类实现 Set 接口,提供所有的丰富性、类型安全性和 与任何其他 Set 实现的互操作性。但 在内部,每个 EnumSet 都表示为一个位向量。如果 底层枚举类型有 64 个或更少的元素——而且大多数都有 -- 整个 EnumSet 用一个 long 表示,所以它的性能相当于一个位域。批量操作, 如removeAll和retainAll,是使用bit-wise实现的 算术,就像您手动为位字段所做的那样。但你是 与手动钻头的丑陋和易错性隔离开来 玩弄。 EnumSet 为您完成了艰苦的工作。

        所以我们可以做这样的事情。

        public class SizeSet {
        
          public enum Size {S, M, L, XL, XXL, XXXL}
        
          public void applySize(Set<Size> sizes){}
        
        }
        

        调用它的客户端代码可能会执行类似的操作

        SizeSet largeSizeSet = new SizeSet();
        largeSizeSet.applySize(EnumSet.of(Size.L, Size.XXL, Size.XXL));
        

        请注意,applySize 方法采用Set&lt;Size&gt; 而不是EnumSet&lt;Size&gt;。虽然很漂亮 很明显并且很可能客户端会将 EnumSet 传递给方法,因此接受接口而不是具体实现是一个好习惯。

        【讨论】:

          【解决方案5】:

          EnumSet 专门用于存储枚举类型元素并快速迭代它。 例如。

          for (Day d : EnumSet.range(Day.MONDAY, Day.FRIDAY))
                  System.out.println(d);
          

          上面的 sn-p 将显示从星期一到星期五的星期几。

          【讨论】:

            【解决方案6】:

            根据Oracle doc

            枚举集在内部表示为位向量。这种表示非常紧凑和高效。

            可读、类型安全、内存占用少...您还想要什么?

            【讨论】:

              【解决方案7】:

              举个例子:

              ....
              public static final String S = "s";
              public static final String M = "m";
              public static final String L = "l";
              ....
              
              Set<String> sizeSet = new HashSet<String>();
              sizeSet.add(S);
              sizeSet.add(M);
              

              那么,上面例子中的 sizeSet 是什么?

              EnumSet 与上面的例子没有什么不同,只是 EnumSet 是一个特殊的 Set 实现,可以与枚举类型一起工作并优化,仅此而已。

              【讨论】:

                【解决方案8】:
                EnumSet largeSize
                

                EnumSet largeSize 是一组枚举值,包含 XL、XXL 和 XXXL。

                Size 
                

                Size 是 Enum 类型的一类,有常量值 S、M、L、XL、XXL、XXXL。

                largeSize.iterator()
                

                EnumSet 的迭代器采用自然顺序,即最初声明枚举值的顺序。

                • EnumSet 类是 Java 集合框架的成员并且未同步。
                • 它是一个高性能的集合实现,它们比 哈希集。
                • 每个 EnumSet 实例的所有元素都必须是 单个枚举类型。

                要了解更多信息,请阅读 api 文档:http://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html

                【讨论】:

                  【解决方案9】:

                  EnumSet 是一个专门的 Set 集合,用于处理枚举类。它实现了Set接口并从AbstractSet扩展:

                  当您计划使用 EnumSet 时,您必须考虑以下几点:

                  1. 它只能包含枚举值,并且所有值都必须属于 相同的枚举
                  2. 它不允许添加空值,尝试这样做会抛出 NullPointerException
                  3. 它不是线程安全的,所以 如果需要,我们需要在外部同步它
                  4. 元素是 按照它们在枚举中声明的顺序存储
                  5. 它使用在副本上工作的故障安全迭代器,因此它不会抛出 ConcurrentModificationException 如果集合被修改时 迭代它

                  现在,EnumSet largeSize 部分是一个变量声明,所以是的,它是 EnumSet 类型。请注意,您可以在集合中添加元素的类型以获得更好的类型安全性:EnumSet&lt;Size&gt;

                  查看这篇文章到learn more about EnumSet

                  【讨论】:

                    【解决方案10】:

                    它可以快速将任何 Enum 元素变成一个集合,EnumSet 是另一种 Set。

                    public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
                    
                    EnumSet.of(Style.BOLD, Style.ITALIC);
                    

                    【讨论】:

                      猜你喜欢
                      • 2017-05-06
                      • 2012-03-30
                      • 2011-10-10
                      • 2012-01-30
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-02-02
                      相关资源
                      最近更新 更多