enum's constant value adding onymous class

user7294900 :

What are the usages of adding onymous (not anonymous) class method in class body in enum's constant values declaration?

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;
    }

How do I access/execute such method ? I find anonymous class example, which isn't recommended

As a recommendation, make your enum implement your interface to make the code more readable

I didn't find usages in JLS's Enum Constants section

The optional class body of an enum constant implicitly defines an anonymous class declaration (§15.9.5) that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes; in particular it cannot contain any constructors.

Instance methods declared in these class bodies may be invoked outside the enclosing enum type only if they override accessible methods in the enclosing enum type.

Ralf Kleberhoff :

TL;DR It's hard to imagine a real-world situation where defining an inner class inside of an enum constant makes sense.

Let's start from your code example...

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;
    }
}

As FAILED is an enum value with a body, it becomes an anonymous subclass of the Status enum class. And Test is defined inside this anonymous class. Because of the anonymous nature of its enclosing class, there's no way to express its name from outside of FAILED. It surely isn't Status.FAILED.Test.

So Test is mainly useful inside of FAILED (if FAILED's implementation is complex enough to warrant an inner class). Generally, I'd prefer enum constants to not become that complex, but that's a matter of style.

An access to Test from outside of FAILED is only possible through a superclass or interface that Test extends / implements, and only to methods exposed through that superclass or interface.

A (contrived) example showing both a usage inside and outside of FAILED, might be:

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

(Added later)

Of course, in this example there's no reason why the Runnable should get a class name. I'd typically use a named inner class instead of an anonymous one only if it's

  • used in multiple places or
  • so complex that it would make the enclosing method unreadable.

That's always the same decision when introducing an anonymous vs. a named inner class. With enums there's even less reason to give the inner class a name, as this name isn't usable outside. So, if I were to see a code like above, I'd refactor it to use an anonymous class:

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

In both cases, the inner class itself isn't visible to outside code, only inside the enum constant, and if the enum constant's implementation gets so complex that it warrants a named inner class, I'd surely refactor it, e.g. by delegating the complexity to some normal top-level class.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=160133&siteId=1