使用enum.values()与String数组时是否有性能损失?

Asa*_*saf 18 java performance enums

我正在使用枚举来替换String我的Java应用程序中的常量(JRE 1.5).

当我将enum视为不断调用的方法中的静态名称数组时(例如,在呈现UI时),是否会影响性能?

我的代码看起来有点像这样:

public String getValue(int col) {
  return ColumnValues.values()[col].toString();
}
Run Code Online (Sandbox Code Playgroud)

澄清:

  • 我关注与values()重复枚举相关的隐藏成本(例如,在paint()方法内部).
  • 我现在可以看到我的所有场景包括一些int=> enum转换 - 这不是Java的方式.

提取values()数组的实际价格是多少?这甚至是个问题吗?

Android开发者

请阅读下面的Simon Langhoff的答案,Geeks On Hugs在接受的答案评论中已经指出了这一点.Enum.values() 必须做一个防御性的副本

Joe*_*han 16

Enum.values()为您提供对数组的引用,并且迭代一个枚举数组的成本与迭代一个字符串数组相同.同时,将字符串值与其他枚举值进行比较实际上可以更快地将字符串与字符串进行比较.

同时,如果您担心调用该values()方法的成本与已经拥有该数组的引用,请不要担心.Java中的方法调用(现在)非常快,并且无论何时它对性能都很重要,无论如何,编译器都会内联方法调用.

所以,说真的,不要担心. 相反,请专注于代码可读性,并使用,Enum以便编译器在尝试使用代码不希望处理的常量值时捕获它.


如果您对为什么枚举比较可能比字符串比较更快感兴趣,请参阅以下详细信息:

这取决于字符串是否已被实习.对于Enum对象,系统中每个枚举值总是只有一个实例,因此每次调用Enum.equals()都可以非常快速地完成,就像使用==运算符而不是equals()方法一样.事实上,对于Enum对象,使用它==代替安全是可以安全的equals(),而对于字符串则不安全.

对于字符串,如果字符串已被实现,那么比较与使用字符串一样快Enum.但是,如果字符串尚未实现,则该String.equals()方法实际上需要遍历两个字符串中的字符列表,直到其中一个字符串结束或发现两个字符串之间不同的字符.

但同样,这可能无关紧要,即使在Swing渲染代码必须快速执行.:-)


@Ben Lings指出Enum.values()必须做一个防御性的副本,因为数组是可变的,你可以替换返回的数组中的值Enum.values().这意味着您必须考虑该防御性副本的成本.但是,复制单个连续数组通常是一种快速操作,假设它是使用某种内存复制调用"在引擎盖下"实现的,而不是天真地迭代数组中的元素.所以,我认为这不会改变最终答案.

  • `Enum.values()`不能给你一个静态数组的引用.如果你更改了它的值,会发生什么?每次调用方法时我都要复制它. (6认同)
  • “所以,说真的,不用担心。” 当需要最大程度地减少开销时,在移动设备上呢?我想知道仅使用一些字节常量而不是创建枚举类型?(专门针对Android) (3认同)

Sim*_*off 15

对于枚举,为了保持不变性,每次调用Values()方法时,它们都会克隆支持数组.这意味着它会对性能产生影响.多少取决于您的具体情况.

我一直在监控我自己的Android应用程序,发现这个简单的调用使用了13.4%的CPU时间!在我的具体情况下.

为了避免克隆values数组,我决定简单地将值缓存为私有字段,然后在需要时循环遍历这些值:

private final static Protocol[] values = Protocol.values();
Run Code Online (Sandbox Code Playgroud)

在这个小优化之后,我的方法调用仅占用了可忽略不计的0.0%CPU时间

在我的用例中,这是一个受欢迎的优化,但是,重要的是要注意使用这种方法是对枚举的可变性的权衡.一旦你给他们一个参考,谁知道人们可能会把什么放进你的数组!?

  • @skiwi在这种情况下,当我要求这个枚举的可能值时,我会得到一个包含所述值的数组的引用.因为我有这个引用,我可以向它添加元素,并且下次有人要求这个枚举的值时,它们将获得对我刚操作的相同数组的引用.因此,任何询问此枚举值的人都会看到之前对后备阵列所做的任何更改. (4认同)