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

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

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

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

 public String getValue(int col) { return ColumnValues.values()[col].toString(); } 

澄清:

  • 我关心的是与重复枚举values()相关的隐藏成本(例如在paint()方法中)。
  • 我现在可以看到我的所有场景都包含一些int => enum转换 – 这不是Java的方式。

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

Android开发者

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

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

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

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


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

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

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

但同样,这可能无关紧要,即使在Swing呈现必须快速执行的代码中也是如此。 🙂


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

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

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

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

 private final static Protocol[] values = Protocol.values(); 

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

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

根据经验:在考虑优化之前,您是否知道此代码可能会降低您的应用程序速度?

现在,事实。

enum在很大程度上是分散在编译过程中的语法糖。 因此,为枚举类定义的values方法返回一个静态集合(也就是说在类初始化时加载),其性能可以被认为大致相当于一个数组。

如果你担心表现,那就测量一下。

从代码中,我不会指望任何意外,但90%的性能猜测是错误的。 如果您想要安全,请考虑将枚举移动到调用代码中(即public String getValue(ColumnValues value) {return value.toString();} )。

用这个:

 private enum ModelObject { NODE, SCENE, INSTANCE, URL_TO_FILE, URL_TO_MODEL, ANIMATION_INTERPOLATION, ANIMATION_EVENT, ANIMATION_CLIP, SAMPLER, IMAGE_EMPTY, BATCH, COMMAND, SHADER, PARAM, SKIN } private static final ModelObject int2ModelObject[] = ModelObject.values(); 

如果您只是为了查找特定值来迭代枚举值,则可以将枚举值静态映射到整数。 这会对性能负载产生性能影响,并且可以根据映射的参数轻松/低影响地获取特定的枚举值。

 public enum ExampleEnum { value1(1), value2(2), valueUndefined(Integer.MAX_VALUE); private final int enumValue; private static Map enumMap; ExampleEnum(int value){ enumValue = value; } static { enumMap = new HashMap(); for (ExampleEnum exampleEnum: ExampleEnum.values()) { enumMap.put(exampleEnum.value, exampleEnum); } } public static ExampleEnum getExampleEnum(int value) { return enumMap.contains(value) ? enumMap.get(value) : valueUndefined; } } 

我想是的。 并且使用常量更方便。