Enum implementing interface, interface and method visibility
Asked Answered
W

3

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?

Wenwenceslaus answered 22/5, 2014 at 15:43 Comment(1)
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.Mauriciomaurie
S
4

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!

Splay answered 22/5, 2014 at 15:49 Comment(4)
So Java was so nice to add the method to MyEnum as well as every constant is effectively implementing it?Wenwenceslaus
@skiwi: Well it doesn't actually add it to the byte code as far as I can see - but it's implicitly there.Splay
So that Java 8 method token is duck-typed?Athens
@chrylis: No, it's using inheritance in the same way that the example I've shown does (it's able to call publicMethod).Splay
M
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.

Miscreance answered 22/5, 2014 at 15:49 Comment(0)
G
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().

Generalist answered 22/5, 2014 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.