Java Enums - 在枚举上切换语句与访问者模式 - 性能优势?

时间:2010-01-29 18:14:50

标签: java enums performance switch-statement visitor-pattern

我一直在寻找几天来找到这个基于效果的问题的答案 到目前为止,在挖掘了Internet之后,我了解到有几种方法可以在java中使用Enums,这在here中有详细记载。 好吧,作为初学者,我希望在 switch-case 语句中使用Enums,这样可以提供清晰度并更好地理解代码。但另一方面,我们还有一个访问者模式样式的Enums实现,它确保了类型的安全性和可扩展性,讨论here

话虽如此,并回到这个问题背后的原始想法,到目前为止,我已经了解到如果使用Enums正确设计switch-case结构,这确保了案例值不稀疏,并且Enum声明是在与switch-case语句相同的编译单元中,java编译器通过实现跳转表这样的构造对生成的字节码执行一些优化(在here和其他地方讨论过)在Sun的网站上,我丢失了链接)。现在,与多个/嵌套的if-else构造相比,这肯定会提升性能。

我的问题是,java如何在生成的字节码中实现基于访问者模式的Enums实现,与基于 switch-case 的实现(如果有)相比,性能提升了多少? / p>

我应该选择哪种类型的实现,考虑到我的枚举可能在将来增长,我也热衷于性能。目前,我的Enum中有19个奇数常数。


修改
我有一个类存储有关游戏变量的一些信息。其中一个变量是 Enum 类型。

public class GameObject {
    private Shape mShape;

    public Shape getShape() {
        return mShape;
    }
    .
    .
    .

    public static enum Shape {
        SHAPE1, SHAPE2, SHAPE3, SHAPE4, ..., SHAPE20
    };

    public void drawShape() {
        switch (this.mShape) {
        case SHAPE1:
            drawShape1();
            break;
        case SHAPE2:
            drawShape2();
            break;
        case SHAPE3:
            drawShape3();
            break;
        case SHAPE4:
            drawShape4();
            break;
        .
        .
        .
        .
        .
        case SHAPE20:
            drawShape20();
            break;
        default:
            drawUnknown();
            break;
        }
    }

}

后来我意识到将信息与逻辑分离,因此创建了另一个类,并从 GameObject <移动 Enum Shape / strong>到这个新类 GraphicModel ,而不是在那里使用 switch-case ,我实现了常量特定的方法。是的,我在这个修改后确实在任一类中都放了适当的import语句。

public class GraphicModel {
    public void drawGraphicFromObject(GameObject gameObject) {
        gameObject.getShape().draw();
    }

    public static enum Shape {
        // This method is not public, instead is only called by GraphicModel
        abstract void draw();

        SHAPE1 {
            @Override
            void draw() {
                // some transformations
            }
        },
        SHAPE2 {
            @Override
            void draw() {
                // Some different transformation
            }
        },
        SHAPE3 {
            @Override
            void draw() {
                // Yet another transform
            }
        },
        .
        .
        .
        .
        UNKNOWN {
            @Override
            void draw() {
                // 
            }
        };
    }
}

后来我甚至按照建议here

基于访客模式实现了这一点

那么,我需要知道的是哪种实施方式更有效?当然,要在编译时将 switch-case 转换为跳转表,java需要 enum 声明和开关同一编译单元中的语句。 我应该在 GraphicModel 类中使用基于 switch 的实现或常量特定方法实现吗? 相反,要明确,性能有何不同?

1 个答案:

答案 0 :(得分:4)

一般来说,如果在 switch 语句(1)中使用,则枚举的性能与 int 常量相当。

也许您应该考虑常量特定方法实现的内容? e.g。

public enum Mode {

  ON { Color color() {return Color.GREEN;}},
  OFF { Color color() {return Color.RED;}},
  STANDBY { Color color() {return Color.YELLOW;}},
  DEFAULT { Color color() {return Color.BLACK;}};

  abstract Color color();

}//enum Mode

然后使用

getMode().color();

而不是开关语句?!

但是,我认为对于“仅获得颜色的情况”,可能根本不需要任何方法。

一般来说,我强烈建议你Effective Java为你的书架。第6章将讨论 Enums和Annotations