постоянное значение enum, добавляющее одноименный класс - PullRequest
0 голосов
/ 23 февраля 2019

Каковы способы добавления одноименного (не анонимного) метода класса в тело класса в объявлении константных значений enum?

public enum Status {
    SUCCESS("SUCCESS"){},FAILED("FAILED"){  
         class Test { 
               public void test() {
                  System.out.println("test");
               }
         }
    };
    private String code;

    Status(String code) {
        this.code = code;
    }

Как получить доступ / выполнить такой метод?Я нахожу пример анонимный класс , который не рекомендуется

В качестве рекомендации сделайте так, чтобы ваш enum реализовал ваш интерфейс, чтобы сделать код более читабельным

Я не нашел использования в разделе JLS Константы Enum

Необязательное тело класса константы enum неявно определяет объявление анонимного класса (§15.9.5), котороерасширяет сразу включающий тип enum.Тело класса регулируется обычными правилами анонимных классов ;в частности, он не может содержать конструкторов.

Методы экземпляра, объявленные в этих телах классов, могут вызываться вне включающего типа перечисления , только если они переопределяют доступные методы во включающем типе перечисления .

1 Ответ

0 голосов
/ 24 февраля 2019

TL; DR Трудно представить реальную ситуацию, когда определение внутреннего класса внутри константы перечисления имеет смысл.

Давайте начнем с вашего примера кода ...

public enum Status {
    SUCCESS("SUCCESS") {

    },
    FAILED("FAILED") {  
        class Test { 
            public void test() {
                System.out.println("test");
            }
        }
    };
    private String code;

    Status(String code) {
        this.code = code;
    }
}

Поскольку FAILED является значением перечисления с телом, оно становится анонимным подклассом класса перечисления StatusTest определен внутри этого анонимного класса.Из-за анонимной природы включающего его класса нет способа выразить его имя за пределами FAILED.Конечно, это не Status.FAILED.Test.

Так что Test в основном полезен внутри FAILED (если реализация FAILED достаточно сложна, чтобы гарантировать внутренний класс).Как правило, я бы предпочел, чтобы константы enum не становились такими сложными, но это вопрос стиля.

Доступ к Test извне FAILED возможен только через суперкласс или интерфейс, который Test расширяет / реализует и только для методов, предоставляемых через этот суперкласс или интерфейс.

(Придуманный) пример, показывающий использование как внутри, так и за пределами FAILED, может быть:

public class StatusTest {

    enum Status {
        FAILED{  
            class Test implements Runnable { 
                private String text = "Test " + System.currentTimeMillis();
                @Override
                public void run() {
                    System.out.println(text);
                }
            }
            @Override
            public Runnable getRunner() {
                return new Test();
            }
            @Override
            public void message() {
                getRunner().run();
            }
        };
        public abstract void message();
        public abstract Runnable getRunner();
    }

    public static void main(String[] args) {
        Status status = Status.FAILED;
        status.message();
        Runnable runner = status.getRunner();
        runner.run();
    }
}

(Добавлено позже)

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

  • используется в нескольких местах или
  • настолько сложен, что делает метод включения нечитаемым.

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

public class StatusTest {

    enum Status {
        FAILED { 
            @Override
            public Runnable getRunner() {
                return new Runnable() { 
                    private String text = "Test " + System.currentTimeMillis();
                    @Override
                    public void run() {
                        System.out.println(text);
                    }
                };
            }
            @Override
            public void message() {
                getRunner().run();
            }
        };
        public abstract void message();
        public abstract Runnable getRunner();
    }

    public static void main(String[] args) {
        Status status = Status.FAILED;
        status.message();
        Runnable runner = status.getRunner();
        runner.run();
    }
}

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

...