Java Enums - операторы Switch против шаблонов посетителей в Enums - преимущества в производительности? - PullRequest
7 голосов
/ 29 января 2010

Я искал несколько дней, чтобы найти ответ на этот вопрос, основанный на производительности.
Покопавшись в Интернете, я узнал, что есть несколько способов использования Enums в java, хорошо документированных в здесь . Что ж, определенно для начала хотелось бы использовать Enums в операторе switch-case , который обеспечивает ясность и лучшее понимание кода. Но с другой стороны, у нас есть реализация типа Enums в стиле Visitor * , которая обеспечивает безопасность типов и расширяемость. Обсуждается здесь .

Сказав это и вернувшись к первоначальной идее, стоящей за этим вопросом, я до сих пор узнал, что если конструкция переключающего регистра правильно спроектирована с использованием Enums, что гарантирует, что значения регистра не редки, и что объявление Enum в том же модуле компиляции, что и оператор switch-case, java-компилятор выполняет некоторую оптимизацию по произведенному байт-коду путем реализации такой конструкции, как таблица переходов (обсуждается в здесь и в других местах а также на сайте Sun, на который я потерял ссылку). Теперь это определенно повышает производительность по сравнению с множественной / вложенной конструкцией if-else.

Мой вопрос заключается в том, как java реализует реализацию Enums на основе шаблонов посетителей в результирующем байт-коде и каково повышение производительности по сравнению с реализацией на основе switch-case , если есть?

И какой тип реализации я бы предпочел, учитывая, что мои Enums могут вырасти в будущем, и я также заинтересован в производительности. В настоящее время в моем Enum есть около 19 с лишним констант.


EDIT
У меня есть класс, который хранит некоторую информацию о переменных игры. Одной из переменных является тип 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;
        }
    }

}

Позже я понял, что нужно отделить информацию от логики, и поэтому создал другой класс и переместил Enum Shape из GameObject в этот новый класс GraphicModel , и вместо того, чтобы switch-case там, я реализовал методы, специфичные для констант . И да, я поместил правильные операторы импорта в любой класс после этой модификации.

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() {
                // 
            }
        };
    }
}

Позже я даже реализовал это на основе шаблона посетителя , как предлагалось здесь

Итак, что мне нужно знать, так это то, какой способ реализации более эффективен? Определенно, для преобразования switch-case в таблицы переходов при компиляции java требует как декларации enum , так и операторов switch в одном и том же блок компиляции . Должен ли я использовать switch основанную реализацию или постоянного метода реализацию в моем GraphicModel классе? Скорее, чтобы было ясно, в чем разница в производительности?

1 Ответ

4 голосов
/ 29 января 2010

Перечисления, вообще говоря, сравнимы по производительности с константами int , если используются в операторе switch ( 1 ).

Может быть, вам следует рассмотреть что-то вроде реализаций метода, специфичного для констант ? например,

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();

вместо оператора switch ?!

Тем не менее, я думаю, что для «получения только цвета», возможно, нет нужды в методах вообще.

В общем, я настоятельно рекомендую вам Эффективная Java для вашей книжной полки. В главе 6 будет обсуждаться Перечисления и аннотации .

...