Search code examples
javainterfaceenumspackage-private

Enum implementing interface, interface and method visibility


I just came accross the following code, which surprised me a little bit, I converted it to a simple SSCEE here though:

custompackage.package1.MyEnum.java

public enum MyEnum implements MyInterface {
    CONSTANT_ONE() {
        @Override
        public void myMethod() {
            //do something very interesting
        }
    },
    CONSTANT_TWO() {
        @Override
        public void myMethod() {
            //do something very interesting
        }
    };
}

interface MyInterface {
    void myMethod();
}

Now from outside this package, I can do the following:

Consumer<MyEnum> myMethod = MyEnum::myMethod;

However I am not able to use MyInterface at all, which I understand as it is package-private to custompackage.package1.

I don't understand what exactly is going on though, it seems like MyEnum got the myMethod() method added, but it does not implement (from the outside) MyInterface.
How does this work?


Solution

  • Well you can't see MyInterface from outside the package, as you said - but MyEnum effectively has a public abstract myMethod() method, which you're able to use as a method reference.

    Leaving aside fancy new Java 8 features, this is valid (even outside the package):

    // Even MyEnum x = null; will compile, but obviously fail
    MyEnum x = MyEnum.CONSTANT_ONE;
    x.myMethod();
    

    The method is inherited from the interface, even though the interface itself is not visible.

    This isn't specific to interfaces and enums, either. For example:

    // Foo.java
    package foo;
    
    class SuperFoo {
       public void publicMethod() {
       }
    }
    
    public class Foo extends SuperFoo {
    }
    
    // Bar.java
    package bar;
    
    import foo.Foo;
    
    public class Bar {
        public void test() {
            Foo foo = new Foo();
            foo.publicMethod();
        }
    }
    

    This compiles fine, even though Foo doesn't even override publicMethod. As far as Bar is concerned, it's inherited from somewhere, but it doesn't know where!