实现接口的枚举, 接口和方法的可见性

7
我刚刚看到了以下代码,有些惊讶,但我将其转换成了一个简单的SSCEE示例: 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();
}

现在在包外,我可以执行以下操作:
Consumer<MyEnum> myMethod = MyEnum::myMethod;

然而,我完全无法使用 MyInterface ,我理解这是因为它只能在 custompackage.package1 中使用。

不过,我并不理解发生了什么,似乎 MyEnum 添加了 myMethod()方法,但它从外部看来并没有实现 MyInterface
这是如何运作的?


只是猜测,也许接口强制 MyEnum 实现 myMethod(),但从外部来看,任何使用 MyEnum 的用户只会发现它恰好有一个名为 myEnum() 的方法,然而用户对 myEnum() 实现的接口方法一无所知。 - forgivenson
3个回答

5

正如您所说,从包外部无法看到MyInterface,但是MyEnum实际上具有一个公共的抽象myMethod()方法,您可以将其用作方法引用。

抛开新颖的Java 8功能不谈,以下代码是有效的(即使在包外部):

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

该方法继承自接口,即使该接口本身不可见。
这不仅适用于接口和枚举。例如:
// 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();
    }
}

这个编译是没有问题的,即使 Foo 没有实现 publicMethod。对于 Bar 来说,它是从 某个地方 继承而来,但是它不知道从哪里继承来的!


那么Java很好地将该方法添加到了MyEnum中,因此每个常量都有效地实现了它? - skiwi
@skiwi: 据我所知,它实际上并没有将其添加到字节码中,但是它是隐式存在的。 - Jon Skeet
Java 8方法令牌是鸭子类型的吗? - chrylis -cautiouslyoptimistic-
1
@chrylis:不,它使用与我展示的示例相同的继承方式(它能够调用publicMethod)。 - Jon Skeet

1

接口中的方法默认为public abstract。字段是public static final

你可以使用该方法的原因是接口是包局部的。尝试将其设置为public。


1
然而,我无法使用MyInterface,我理解为它是custompackage.package1的包私有(package-private)接口。
该接口是包私有的,但所有方法(和字段)都是(隐式或显式)公共的。
似乎MyEnum添加了myMethod()方法,但从外部来看它并没有实现MyInterface。
MyEnum有一个名为myMethod()的公共方法,无论它是从接口继承的公共抽象方法还是自己声明的方法。换句话说,即使外部无法看到接口,它仍然可以看到MyEnum,并查看MyEnum.myMethod()。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接