7

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?

skiwi
  • 66,971
  • 31
  • 131
  • 216
  • Just a guess, but perhaps the interface forces `MyEnum` to implement `myMethod()`, but then from the outside, any user of `MyEnum` simply sees that it happens to have a method named `myEnum()`, however the user knows nothing about the interface method that `myEnum()` is implementing. – forgivenson May 22 '14 at 15:51

3 Answers3

5

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!

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

In interfaces methods are public abstract by default. fields are public static final

the reason you can use the method is that the interface is package local. Try making it public.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1

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

The interface is package-private, but all methods (and fields) are (implicitly or explicit) public.

it seems like MyEnum got the myMethod() method added, but it does not implement (from the outside) MyInterface.

MyEnum has a public method called myMethod(), regardless of whether it inherited the (public) abstract method from the interface or whether it declared the method itself. Said another way, even if the outside cannot see the interface, the outside can certainly see MyEnum and see MyEnum.myMethod().

Bert F
  • 85,407
  • 12
  • 106
  • 123