Перечисления: методы, исключающие каждый из экземпляров

Из еще один вопрос Я узнал, что в Java возможно определить конкретные методы для каждого из экземпляров Enum:

public class AClass {

    private enum MyEnum{
        A { public String method1(){ return null; } },
        B { public Object method2(String s){ return null; } },
        C { public void method3(){ return null; } } ;
    }

    ...
}

Я был удивлен, что это даже возможно, для этого "эксклюзивные методы", специфичные для каждого экземпляра, есть имя для поиска документации?

Кроме того, как он должен использоваться? Потому что следующее не компилируется:

    private void myMethod () {
        MyEnum.A.method1();
    }

Как я могу использовать эти "эксклюзивные" методы?

Ответ 1

Вы не можете ссылаться на эти методы, потому что вы эффективно создаете анонимный (*) класс для каждого перечисления. Поскольку это анонимно, вы можете ссылаться на такие методы только внутри вашего анонимного класса или через отражение.

Этот метод в основном полезен, когда вы объявляете абстрактный метод в своем перечислении и реализуете этот метод для каждого перечисления в отдельности.

(*) JLS 8.9 Enums part говорит: "Необязательное тело класса константы enum неявно определяет анонимное объявление класса (§15.9.5), которое расширяет сразу включаемый тип перечисления".

Ответ 2

Вам нужно объявить абстрактные методы в вашем перечислении, которые затем реализованы в конкретных экземплярах enum.

class Outer {

    private enum MyEnum {
        X {
            public void calc(Outer o) {
                // do something
            }
        },
        Y {
            public void calc(Outer o) {
                // do something different
                // this code not necessarily the same as X above
            }
        },
        Z {
            public void calc(Outer o) {
                // do something again different
                // this code not necessarily the same as X or Y above
            }
        };

        // abstract method
        abstract void calc(Outer o);
    }

    public void doCalc() {
        for (MyEnum item : MyEnum.values()) {
            item.calc(this);
        }
    }
}

Ответ 3

Каждый enum является анонимным внутренним классом. Поэтому, как и любой анонимный внутренний класс, вы можете добавить все нужные вам методы, но нет способа ссылаться на них вне класса, поскольку класс не имеет типа, определяющего методы.

Преимущество предоставления методам реализации enum заключается в том, что он позволяет использовать шаблон стратегии, где сам перечисление имеет абстрактный метод или реализацию по умолчанию, а конкретные члены enum имеют реализации этого метода, которые может сделать что-то другое.

Я использовал этот метод, чтобы значительно снизить сложность кода в операторах switch. Вместо включения перечисления в каком-либо другом классе просто получите ссылку на него и вызовите метод, и пусть enum сам позаботится об этом. Конечно, это зависит от сценария, если это имеет смысл, но это может значительно уменьшить сложность кода.