天道酬勤,学无止境

Why an EnumSet or an EnumMap is likely to be more performant than their hashed counterparts?

The following is from the Implementation Note section of Java doc of EnumMap :

Implementation note: All basic operations execute in constant time. They are likely (though not guaranteed) to be faster than their HashMap counterparts.

I have seen a similar line in the java doc for EnumSet also . I want to know why is it more likely that EnumSets and EnumMaps will be more faster than their hashed counterparts ?

评论

EnumSet is backed by a bit array. Since the number of different items you can put in EnumSet is known in advance, we can simply reserve one bit for each enum value. You can imagine similar optimization for Set<Byte> or Set<Short>, but it's not feasible for Set<Integer> (you'd need 0.5 GiB of memory for 2^32 bits) or in general.

Thus basic operations like exists or add ar constant time (just like HashSet) but they simply need to examine or set one bit. No hashCode() computation. This is why EnumSet is faster. Also more complex operations like union or easily implemented using bit manipulation techniques.

In OpenJDK there are two implementations of EnumSet: RegularEnumSet capable of handling enum with up to 64 values in long and JumboEnumSet for bigger enums (using long[]). But it's just an implementation detail.

EnumMap works on similar principles, but it uses Object[] to store values while key (index) is implicitly inferred from Enum.ordinal().

EnumSet uses array[] inside and a natural order with consequent consequences:

  • fast: get/set is called by constant time O(1), hashCode() is not used to find a right bucket
  • memory efficiency: the size of array is predefined by Enum size and is not dynamic

EnumMap uses Enum as a key based on the same principals as EnumSet where hash code collision is not possible

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 枚举:为什么? 什么时候?(Enumerations: Why? When?)
    问题 我是一名即将毕业的计算机科学专业的学生,​​在我的整个编码生涯中,我发现很少使用枚举的实例,除了典型的情况(例如代表标准纸牌的面孔)外,还使用了枚举。 您是否知道在日常编码中使用枚举的任何巧妙方法? 为什么枚举如此重要,在什么情况下应该能够确定建立枚举是最好的方法? 回答1 通过简短示例,这些是enum,EnumMap和EnumSet的主要参数。 enum的情况 从Java 6开始,java.util.Calendar是一个凌乱类的示例,该类可以从使用enum受益匪浅(除其他改进外)。 当前Calendar定义了以下常量(还有许多其他常量): // int constant antipattern from java.util.Calendar public static final int JANUARY = 0; public static final int FEBRUARY = 1; ... public static final int SUNDAY = 1; public static final int MONDAY = 2; ... 这些都是int ,即使它们显然表示不同的概念实体。 以下是一些严重的后果: 它很脆; 在需要时必须小心分配不同的编号。 如果错误地将MONDAY = 0;设置MONDAY = 0;设置MONDAY = 0; , SUNDAY =
  • Java中的枚举。 优点?(Enum in Java. Advantages?)
    问题 使Java中的枚举类似于类而不是像C / C ++那样仅是常量集合有哪些优点? 回答1 您可以获得有效值的免费编译时检查。 使用 public static int OPTION_ONE = 0; public static int OPTION_TWO = 1; 不保证 void selectOption(int option) { ... } 将仅接受0或1作为参数值。 使用枚举是可以保证的。 此外,由于您可以使用代码完成功能来查看所有枚举值,因此这会导致更多的自我记录代码。 回答2 类型安全是原因之一。 我发现更重要的另一点是,您可以将元数据附加到Java中的枚举值中。 例如,您可以使用一个枚举来定义Web服务的合法操作集,然后为请求和数据类的类型附加元数据: AddItem(HttpMethod.POST, ProductEntry.class), 回答3 Java 5枚举源自Joshua Bloch的Effective Java(第一版)的类型安全枚举模式,以避免C / C ++ / C#中的枚举的陷阱(它们只是薄薄的int常量)以及在Java中使用最终静态int常数。 主要是int常量和int枚举不是类型安全的。 您可以传入任何int值。 在C / C ++中,您可以执行以下操作: enum A { one, two, three }; enum B { beef
  • 是否有任何原因EnumMap和EnumSet不可导航(Is there any reason EnumMap and EnumSet are not Navigable)
    问题 枚举是可比的,这意味着您可以 NavigableSet<AccessMode> modes = new TreeSet<>(); NavigableMap<AccessMode, Object> modeMap = new TreeMap<>(); 这些具有O(ln N)访问时间。 枚举集合具有O(1)访问时间,但不可导航 NavigableSet<AccessMode> modes = EnumSet.noneOf(AccessMode.class); // doesn't compile NavigableMap<AccessMode, Object> modeMap = new EnumMap<>(AccessMode.class); // doesn't compile 我想知道是否有一个原因,枚举集合不可导航(和排序)。 即我想念什么吗? 回答1 我最好的猜测是,可导航性并未被视为枚举集的主要用例。 在实现中,没有什么会阻止可导航性。 TreeSet和TreeMap涵盖了将一组枚举成员的需要与可导航性结合在一起的罕见用例。 回答2 JDK及其各种API缺少许多“显而易见的”功能。 为什么忽略/遗忘了此特定功能? 我们只能猜测。 但是您的问题很长时间以来一直是Sun / Oracle的RFE: http://bugs.sun.com/bugdatabase/view
  • 与具有公共静态final字段的类相比,Java枚举有什么优势?(What's the advantage of a Java enum versus a class with public static final fields?)
    问题 我对C#非常熟悉,但是开始在Java中工作更多。 我希望了解到Java中的枚举基本上与C#中的枚举等效,但显然并非如此。 最初,我很高兴得知Java枚举可以包含多条数据,这似乎非常有利(http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html)。 但是,从那时起,我发现了很多C#缺少的功能,例如能够轻松地为enum元素分配特定值的功能,以及因此无需花费大量精力即可将整数转换为enum的功能(即将整数值转换为匹配的Java枚举)。 所以我的问题是:与具有一堆公共静态final字段的类相比,Java枚举对Java枚举有什么好处吗? 还是只是提供更紧凑的语法? 编辑:让我更清楚。 与具有一堆相同类型的公共static final字段的类相比,Java枚举有什么好处? 例如,在第一个链接的“行星”示例中,与具有这些公共常量的类相比,枚举的优势是什么: public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6); public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6); public static final Planet EARTH = new Planet(5
  • Java枚举相对于旧的“ Typesafe枚举”模式的优势?(Advantages of Java's enum over the old “Typesafe Enum” pattern?)
    问题 在JDK1.5之前的Java中,“ Typesafe Enum”模式是实现只能接受有限数量的值的类型的常用方法: public class Suit { private final String name; public static final Suit CLUBS =new Suit("clubs"); public static final Suit DIAMONDS =new Suit("diamonds"); public static final Suit HEARTS =new Suit("hearts"); public static final Suit SPADES =new Suit("spades"); private Suit(String name){ this.name =name; } public String toString(){ return name; } } (例如,参见Bloch的Effective Java中的第21项)。 现在在JDK1.5 +中,“官方”方法显然是使用enum : public enum Suit { CLUBS("clubs"), DIAMONDS("diamonds"), HEARTS("hearts"), SPADES("spades"); private final String name
  • EffectiveJava-5-枚举和注解
    用enum代替int常量 1. int枚举: 引入枚举前,一般是声明一组具名的int常量,每个常量代表一个类型成员,这种方法叫做int枚举模式。 int枚举模式是类型不安全的,例如下面两组常量:性别和动物种类,二者不存在任何关系,然而却可以将ANIMAL_DOG传入一个需要性别参数的方法中,编译器不会出现警告,而且方法内部逻辑还会继续执行比较等操作。 采用int枚举模式的程序是十分脆弱的,因为int枚举是编译时常量,被编译到使用它们的客户端中,如果与枚举常量关联的int值发生变化客户端就必须重新编译,然而不重新编译却不会报错,但是会导致程序的结果不准确,例如上面的常量SEX_MAN被客户端使用,于是将其值1编译到客户端的.class中,然后如果API类中将SEX_MAN的值改为2,却不重新编译客户端,那么客户端得到的结果就是不准确的了。 int枚举常量很难被翻译成可打印的字符串,不利于开发调试。 开发过程中还可能遇到这种模式的变体,如String枚举模式,同样是存在上述问题。 2. 枚举类型: 由一组固定的常量组成的合法值的类型,例如: 实现思路:通过公有静态的final域为每个枚举常量导出实例的类。 枚举类型是类型安全的枚举模式,而且完善类int枚举模式的不足。 枚举类型还允许添加任意的方法和域,并实现任意的接口,它提供类所以Object方法的高级实现
  • 使用Enum的序数值对Java中的数组进行索引是否是不好的做法?(Is it bad practice to use an Enum's ordinal value to index an array in Java?)
    问题 我有两个数组:墙和邻居。 public boolean[] walls = new boolean[4]; public Cell[] neighbors = new Cell[4]; 我有一个枚举: enum Dir { North, South, East, West } 现在,我希望能够按其方向访问墙壁或邻居,因此不必绕过一堆魔术索引。 但是,当我阅读Enum.ordinal()的文档时,它说程序员几乎不会使用此方法,这使我认为不应以这种方式使用它。 我正在考虑做类似的事情: List<Dir> availableDirections = new ArrayList<Dir>(); for(Dir direction : Dir.values()) if (!Neighbors[direction.ordinal()].Visited) availableDirections.add(direction); 甚至: return Neighbors[Dir.North.ordinal()]; 我应该恢复对索引值设置为NORTH,SOUTH,EAST,WEST的静态常量还是使用Enum的序数方法? 回答1 在切线问题上,对邻居使用EnumMap可能更好: Map<Dir, Cell> neighbours = Collections.synchronizedMap(new
  • 2021年JAVA 精心整理的常见面试题-附详细答案【持续更新~~】
    先罗列本篇文章包含的 Java 常见面试的主题: 一、Java基础面试题 二、Java 集合框架 三、Linux常用指令 四、MySQL基础面试 多线程与多进程面试常见设计模式JVM 底层常用网络协议常见的数据结构和算法 关注我们,更多技术干货: 2000多G的计算机各行业电子资源分享(持续更新) 2020年微信小程序全栈项目之喵喵交友【附课件和源码】 Spring Boot开发小而美的个人博客【附课件和源码】 Java微服务实战296集大型视频-谷粒商城【附代码和课件】 Java开发微服务畅购商城实战【全357集大项目】-附代码和课件 最全最详细数据结构与算法视频-【附课件和源码】 2021年JAVA 精心整理的常见面试题-附详细答案 https://mikejun.blog.csdn.net/article/details/114488339 2021年- 精心整理的 SpringMVC 常见面试题-【附详细答案】 https://mikejun.blog.csdn.net/article/details/114992529 2021年JAVA 面试题之--数据结构篇【附详细答案】 https://mikejun.blog.csdn.net/article/details/114647742 三天刷完《剑指OFFER编程题》--Java版本实现(第一天) https:/
  • Enum.hashCode()背后的原因是什么?(What is the reason behind Enum.hashCode()?)
    问题 Enum类中的hashCode()方法是final方法,并定义为super.hashCode(),这意味着它基于实例的地址返回一个数字,该数字是程序员POV的随机数。 将其定义为ordinal() ^ getClass().getName().hashCode()在不同的JVM之间是确定性的。 甚至会做得更好,因为最低有效位会“尽可能多地变化”,例如,对于包含最多16个元素和大小为16的HashMap的枚举,肯定不会发生冲突(请确保,使用EnumMap更好,但有时无法实现,例如,没有ConcurrentEnumMap。 根据当前的定义,您没有这样的保证,对吗? 答案摘要 使用Object.hashCode()可以与更好的hashCode(例如上面的代码Object.hashCode()进行比较,如下所示: 优点简单对比速度更多碰撞(对于任何大小的HashMap) 非确定性,会传播到其他对象,使它们无法用于确定性模拟 ETag计算根据例如HashSet迭代顺序HashSet错误 我个人更喜欢更好的hashCode,但是恕我直言,没有理由称重,也许除了速度之外。 更新 我对速度感到好奇,并写了一个令人惊讶的结果的基准。 对于每个类一个字段的价格,您可以使用确定性哈希码,该哈希码的速度快将近四倍。 尽管可以忽略不计,但将哈希码存储在每个字段中甚至更快。
  • 怒肝俩月,新鲜出炉史上最有趣的Java小白手册,第一版,每个 Java 初学者都应该收藏
    这么说吧,在我眼里,Java 就是最流行的编程语言,没有之一(PHP 往一边站)。不仅岗位多,容易找到工作,关键是薪资水平也到位,不学 Java 亏得慌,对吧? 那可能零基础学编程的小伙伴就会头疼了,网上关于 Java 的大部分技术文章都不够幽默,不够风趣,不够系列,急需要一份能看得进去的学习手册,那我觉得我肝的这份手册正好符合要求,并且会一直持续更新下去。 第一版的内容暂时包含两方面,Java 基础和 Java 面向对象编程。来吧,先上目录,一睹为快。 01、Java 基本语法简介 02、Java 基本数据类型简介 03、Java main() 方法简介 04、Java 的流程控制语句 05、Java 包的简介 06、Java 到底是值传递还是引用传递 07、Java 的类和对象 08、Java 构造方法 09、Java 抽象类 10、Java 接口 11、Java 继承 12、this 关键字 13、super 关键字 14、重写和重载 15、static 关键字 16、Java 枚举 17、final 关键字 目录欣赏完了,接下来就是拜读精华内容的时间,搬个小板凳,认认真真好好学吧,学到就是赚到! 一、Java 基本语法简介 01、数据类型 Java 有 2 种数据类型,一种是基本数据类型,一种是引用类型。 基本数据类型用于存储简单类型的数据,比如说,int、long
  • 《Effective Java》中文版第3版 读书笔记
    评论中有电子档资源哦 ^_^ 第1章引言 第2章创建和销毁对象 第1条:用静态工厂方法代替构造器 静态工厂方法与构造器不同的第一大优势在于,它们有名称。 静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新对象。 它从来不创建对象。 这种方法类似于享元 (Flyweight)模式 。 如果程序经常请求创建相同的对象,并且创建对象的代价 很高,则这项技术可以极大地提升性能。 public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } 静态工厂方法与构造器不同的第三大优势在子,它们可以返回原返回类型的任何子类 型的对象。 静态工厂的第四大优势在于,所返回的对象的类可以随着每次调用而发生变化,这取 决于静态工厂方法的参数值。 EnumSet 没有公有的构造器,只有静态工厂方法。 在 OpenJDK 实现中, 它们返回两种子类之一的一个实例,具体则取决于底层枚举类型的大小:如果它的元素有 64 个或者更少,就像大多数枚举类型一样,静态工厂方法就会返回一个 RegalarEumSet 实例, 用单个 long 进行支持;如果枚举类型有 65 个或者更多元素,工厂就返回 JumboEnumSet 实例,用一个 long 数组进行支持。 /** * Creates an empty
  • java学习记录:java集合框架(更新中)
    Java集合框架概述 集合接口与实现分离 collection接口 collection接口是java类库中集合类的基本接口,其中包含两个基本方法: public interface Collection<E> { boolean add(E element); Iterator<E> iterator(); } 1.add()方法用于向集合中添加元素,若确实改变集合则返回true 2.iterator()用于返回一个实现了迭代器接口的对象 其他方法:(待补全) { ... int size(); boolean isEmpty(); ... } 迭代器 Iterator接口包含四个方法: public interface Iterator<E> { E next(); boolean HasNext(); void remove(); default void forEachRemaining(Consumer<?super E>action); } 1.通过反复调用next()方法可以逐个访问集合中的 每个元素,但若到集合末尾,next()方法将抛出一个NoSuchElementException异常 2.为避免异常的抛出,使用next()方法之前应当先调用hasNext()方法。如果迭代器对象还有多个供访问元素,这个方法就返回true,以此作为判据来反复调用next()方法
  • EnumSet到底是什么意思?(What does EnumSet really mean?)
    问题 我有以下示例: 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类型的对象吗? 这到底是什么意思? 我真的很想更好地理解它。 回答1 至于任何变量,可以在其声明中找到其类型: EnumSet largeSize 因此,是的, largeSize (由于它是一个集合,因此应命名为largeSizes )的类型为EnumSet 。 它也应该被泛化,因此被声明为 EnumSet<Size> largeSizes 它的意思是largeSizes是EnumSet类型。
  • Java接地气日常编码技巧
    Effective Java。Java名著,必读。如果能严格遵从本文的原则,以编写API的质量来苛求自己的代码,会大大提升编码素质。以下内容只记录了我自己整理的东西,还是建议读原文。为了聚焦知识点,一些说明故意忽略掉了。相当于是一篇摘要。1、考虑用静态工厂方法替代构造函数例子:Integer.valueOf(“1”)、Boolean.valueOf(“true”)等。优势:可读性高(方法名)性能(不一定创建对象)灵活性高下面针对三个优势进行一些解读。可读性高new Point(x,y)和Point.at(x,y)、Point.origin()。构造函数只能看出两个参数,不知其意,后者更易理解。性能在某些情况下,可以事先进行实例化一些对象,调用时直接调用即可,不需要进行改变。比如,Boolean。public final class Boolean implements Serializable, Comparable<Boolean> { // 预先设置两个对象 public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); public Boolean(boolean var1) { this.value = var1; }
  • 精选 Java面试题附答案 ---- 字符串&集合面试题篇
    1. Java 中操作字符串都有哪些类?它们之间有什么区别? 操作字符串的类有:String、StringBuffer、StringBuilder。 String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象。 而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。 24万字Java面试手册PDF下载链接:https://shimo.im/docs/Wyj8QRpq39jkC3jD24万字Java面试手册PDF下载链接:https://shimo.im/docs/Wyj8QRpq39jkC3jD24万字Java面试手册PDF下载链接:https://shimo.im/docs/Wyj8QRpq39jkC3jD StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer, 所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。 2
  • Effective Java学习笔记
    静态工厂方法 考虑使用静态工厂方法代替构造 静态工厂方法与构造器不同的第一优势在于,它们有名字 第二个优势,不用每次被调用时都创建新对象 第三个优势,可以返回原返回类型的子类 第四个优势,在创建带泛型的实例时,能使代码变得简洁(jdk1.8已经解决) 除此之外 可以有多个参数相同但名称不同的工厂方法 可以减少对外暴露的属性 多了一层控制,方便统一修改 Java 中,获得一个类实例最简单的方法就是使用 new 关键字,通过构造函数来实现对象的创建。 就像这样: Fragment fragment = new MyFragment(); // or Date date = new Date(); 不过在实际的开发中,我们经常还会见到另外一种获取类实例的方法: Fragment fragment = MyFragment.newIntance(); // or Calendar calendar = Calendar.getInstance(); // or Integer number = Integer.valueOf(“3”); ↑ 像这样的:不通过 new,而是用一个静态方法来对外提供自身实例的方法,即为我们所说的静态工厂方法(Static factory method)。 惯用名称: • from——类型转换方法,它接受单个参数并返回此类型的相应实例,例如:Dated=Date
  • 硬肝4.4w字为你写成Java开发手册
    先来看一下本篇文章的思维导图吧,我会围绕下面这些内容进行讲解。内容很干,小伙伴们看完还希望不吝转发。 下面开始我们的文章。 Java 概述 什么是 Java? Java 是 Sun Microsystems 于1995 年首次发布的一种编程语言和计算平台。编程语言还比较好理解,那么什么是 计算平台 呢? 计算平台是在电脑中运行应用程序(软件)的环境,包括硬件环境和软件环境。一般系统平台包括一台电脑的硬件体系结构、操作系统、运行时库。 Java 是快速,安全和可靠的。 从笔记本电脑到数据中心,从游戏机到科学超级计算机,从手机到互联网,Java 无处不在!Java 主要分为三个版本 JavaSE(J2SE)(Java2 Platform Standard Edition,java平台标准版)JavaEE(J2EE)(Java 2 Platform,Enterprise Edition,java平台企业版)JavaME(J2ME)(Java 2 Platform Micro Edition,java平台微型版)。 Java 的特点 Java 是一门面向对象的编程语言 什么是面向对象?面向对象(Object Oriented) 是一种软件开发思想。它是对现实世界的一种抽象,面向对象会把相关的数据和方法组织为一个整体来看待。 相对的另外一种开发思想就是面向过程的开发思想,什么面向过程
  • 使用Java从日期中识别季节(Identifying the season from the Date using Java)
    问题 我只好运气了,所以为什么不再试一次呢? 我有一个需要根据一年中的季节(春季,夏季,冬季,秋季)显示不同图像的应用程序。 对于这些季节,我有非常具体的开始和结束日期。 我想从您的天才那里得到一个叫GetSeason的方法,该方法将日期作为输入并返回Spring,Summer,W​​inter或Fall的字符串值。 以下是日期范围及其相关的季节: 春季:3 / 1-4 / 30 夏季:5 / 1-8 / 31 秋季:9 / 1-10 / 31 冬季:11 / 1-2 / 28 有人可以提供一种工作方法来返回适当的季节吗? 谢谢大家! 回答1 似乎只检查月份就可以了: private static final String seasons[] = { "Winter", "Winter", "Spring", "Spring", "Summer", "Summer", "Summer", "Summer", "Fall", "Fall", "Winter", "Winter" }; public String getSeason( Date date ) { return seasons[ date.getMonth() ]; } // As stated above, getMonth() is deprecated, but if you start with a Date,
  • Is there any reason EnumMap and EnumSet are not Navigable
    Enum is Comparable which means you can have NavigableSet<AccessMode> modes = new TreeSet<>(); NavigableMap<AccessMode, Object> modeMap = new TreeMap<>(); These have O(ln N) access times. The Enum collections have O(1) access times, but are not Navigable NavigableSet<AccessMode> modes = EnumSet.noneOf(AccessMode.class); // doesn't compile NavigableMap<AccessMode, Object> modeMap = new EnumMap<>(AccessMode.class); // doesn't compile I was wondering if there was a reason Enum collections were not Navigable (and Sorted). i.e Am I missing something?
  • Java枚举:两种枚举类型,每种包含彼此的引用?(Java Enums: Two enum types, each containing references to each other?)
    问题 有没有一种方法可以解决由两个互相引用的枚举引起的类加载问题? 我有两组枚举Foo和Bar,它们的定义如下: public class EnumTest { public enum Foo { A(Bar.Alpha), B(Bar.Delta), C(Bar.Alpha); private Foo(Bar b) { this.b = b; } public final Bar b; } public enum Bar { Alpha(Foo.A), Beta(Foo.C), Delta(Foo.C); private Bar(Foo f) { this.f = f; } public final Foo f; } public static void main (String[] args) { for (Foo f: Foo.values()) { System.out.println(f + " bar " + f.b); } for (Bar b: Bar.values()) { System.out.println(b + " foo " + b.f); } } } 上面的代码作为输出产生: A bar Alpha B bar Delta C bar Alpha Alpha foo null Beta foo null Delta foo null 我知道为什么会发生