Enum的匿名实现无法使用参数引用Enum的私有静态toString - java

给定这个示例代码...

package example;

public class Main {
    public static void main(String[] args) {
        System.out.println(MyEnum.X.getValue());
    }

    private enum MyEnum {
        X(){
            @Override
            String getValue() {
                return toString("XYZ"); //error here
            }
        };

        abstract String getValue();

        private static String toString(String output) {
            return output;
        }
    }
}

产生以下编译器错误:

Error:(12, 40) java: method toString in class java.lang.Enum<E> cannot be applied to given types;
  required: no arguments
  found: java.lang.String
  reason: actual and formal argument lists differ in length

IntelliJ出现了另一个问题:toString中的toString("XYZ")用红色下划线标出,并且显示消息“'toString(java.lang.String)'在'example.Main.MyEnum'中具有私有访问权限”,并带有解决方案“将'MyEnum.toString'打包为私有”。

我感到很奇怪的是,以下任何一项均可解决此问题:

通过枚举引用:X.toString("XYZ")调用该方法。
通过类引用MyEnum.toString("XYZ")调用该方法。
通过super调用方法:super.toString("XYZ")。 (但是this.toString("XYZ")不起作用)
将方法设置为私有或公开
命名方法“ toString2”

现在,对于任何生产代码,我可能会将该方法命名为其他方法(可能是对我将要执行的操作的更多描述),然后继续前进,但是我仍然想知道为什么会发生这种情况?为什么IntelliJ和javac的错误消息不同?

这个问题可能类似于Cannot make a static reference to the non-static field memberVariable with private variable,但是我觉得它不能完全解释问题-为什么重命名有效?

参考方案

首先,此问题并非特定于枚举。它适用于任何内部类。我重构了您的示例以删除该枚举,该枚举在内部类和匿名内部类中都演示了相同的问题。

class Main {
    public static void main(String[] args) {
        Main main = new Main() {
            {
                System.out.println(toString("XYZ")); // same error
            }  
        };
    }

    class Foo {
        {
            System.out.println(toString("XYZ")); // same error
        }
    }

    private static String toString(String output) {
        return output;
    }
}

在JLS here中进行了解释:

示例6.5.7.1-1。简单方法名称

以下程序演示了范围界定的作用
确定要调用的方法。

class Super {
    void f2(String s)       {}
    void f3(String s)       {}
    void f3(int i1, int i2) {}
}

class Test {
    void f1(int i) {}
    void f2(int i) {}
    void f3(int i) {}

    void m() {
        new Super() {
            {
                f1(0);  // OK, resolves to Test.f1(int)
                f2(0);  // compile-time error
                f3(0);  // compile-time error
            }
        };
    }
} 

对于调用f1(0),作用域中只有一个名为f1的方法。这是方法Test.f1(int),其声明在范围内
在整个测试过程中,包括匿名类声明。
由于匿名类,§15.12.1选择在Test类中进行搜索
声明没有名为f1的成员。最终,Test.f1(int)
解决。

对于调用f2(0),两个名为f2的方法在范围内。第一,
方法Super.f2(String)的声明在整个范围内
匿名类声明。二,方法的声明
Test.f2(int)涵盖整个测试范围,包括
匿名类声明。 (请注意,两个声明都没有阴影
另一个,因为在每个被声明的位置,另一个是
不在范围内。)§15.12.1选择在Super类中搜索,因为它
有一个名为f2的成员。但是,Super.f2(String)不适用于
f2(0),因此会发生编译时错误。请注意,类Test不是
搜索。

对于调用f3(0),范围为三个名为f3的方法。第一
第二,方法Super.f3(String)的声明和
Super.f3(int,int)属于整个匿名类的范围
宣言。第三,方法Test.f3(int)的声明位于
整个测试主体的范围,包括匿名类
宣言。 §15.12.1选择搜索类Super,因为它具有
一个名为f3的成员。但是,Super.f3(String)Super.f3(int,int)
不适用于f3(0),因此会发生编译时错误。注意
不搜索类Test

选择先搜索嵌套类的超类层次结构
词汇上包含范围的范围称为“梳子规则”(§15.12.1)。

Java:找到特定字符并获取子字符串 - java

我有一个字符串4.9.14_05_29_16_21,我只需要获取4.9。数字各不相同,所以我不能简单地获得此char数组的前三个元素。我必须找到最正确的.并将其子字符串化直到那里。我来自Python,因此我将展示Python的实现方法。def foobar(some_string): location = some_string.rfind('.&…

Java-搜索字符串数组中的字符串 - java

在Java中,我们是否有任何方法可以发现特定字符串是字符串数组的一部分。我可以避免出现一个循环。例如String [] array = {"AA","BB","CC" }; string x = "BB" 我想要一个if (some condition to tell wheth…

Java:线程池如何将线程映射到可运行对象 - java

试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

JAVA:字节码和二进制有什么区别? - java

java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…

在Java中使用新关键字和直接赋值的字符串 - java

String s="hi"; String s1=new String("hi"); 从内存角度看,s和s1存储在哪里?无论是在堆内存还是堆栈中。s指向“ hi”,而s1指向hi存在的内存位置?请帮忙? 参考方案 考虑以下 String s = "hi"; String s1 = new Strin…