为什么不能在方法中本地声明枚举?

bru*_*nde 55 java enums

今天,我发现自己编写了这样的代码......

public class LocalEnums {

    public LocalEnums() {
    }

    public void foo() {
        enum LocalEnum {
            A,B,C
        };

        // ....
        // class LocalClass { }

    }
}
Run Code Online (Sandbox Code Playgroud)

当编译器报告本地错误时,我有点惊讶enum:

成员枚举LocalEnum不能是本地的

为什么枚举不能像一样在本地声明?

我发现这在某些情况下非常有用.在我工作的情况下,其余的代码不需要知道任何关于enum.

是否有任何结构/设计冲突可以解释为什么这是不可能的,或者这可能是Java 的未来特性?

kdg*_*ory 38

枚举是静态嵌套类,因为它们定义静态成员变量(枚举值),这对于内部类不允许的:http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html #JLS-8.1.3

更新:我正在查看JLS(java语言规范)以获取有关静态嵌套类限制的更多详细信息,并且没有找到它(尽管它可能存在,隐藏在不同的主题下).从纯粹的实现角度来看,没有理由不这样做.所以我怀疑这是一个语言哲学问题:不应该这样做,因此不会得到支持.但我不在那里,所以这是纯粹的猜测.

作为评论:如果你的方法足够大,他们需要自己的枚举,那么这是一个强烈的迹象,你需要重构.

  • kdgregory,我的方法不必那么大,使用枚举的*power*...枚举可以简化/澄清你的代码.因此,重构可能不是问题. (18认同)
  • @dhardy - 语言哲学是*一切*:包括什么,排除什么,以及语言的外观。如果你没有哲学,你就会得到 PHP。 (7认同)
  • 哲学没有理由排除某个特征.缺乏有用性,导致危险代码的可能性(令人惊讶或不明确的行为)和包含的技术难度是正当理由.但我不明白为什么这些适用于此. (5认同)
  • @dhardy 哲学让我们相信一个功能没有用,它可能会导致危险的代码等。这不能客观地评估,Java 有时会有点偏差。+1 到 kdgregory 的 PHP 注释。 (2认同)

Jon*_*eet 15

我很少发现自己在一个方法中编写任何类型,除非它是一个匿名的内部类.但是,您可以编写嵌套枚举:

public class NestedEnum
{
    private enum MyEnum
    {
        X, Y, Z
    }

    public void foo()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

我不认为我真的想一个在其中声明一个新类型的方法 - 你是否有任何具体的理由想要在方法中声明它而不仅仅是一个嵌套类型?我可以看到"没有其他方法需要知道"的论点,但我认为评论可以对此进行排序,并且仍然保留更多可读代码.


Bas*_*que 14

从 2021 年 3 月 16 日发布的 Java 16 开始,其他答案已经过时。

更新:Java 16 中的本地枚举

作为Java 16 中记录功能的一部分,现在可以在本地定义枚举。事实上,记录、枚举和接口现在都可以是本地的

引用 JEP 395:

引入了声明本地记录类、本地枚举类和本地接口的能力。

添加本地记录类是添加其他类型的隐式静态本地声明的机会。

嵌套的枚举类和嵌套的接口已经是隐式静态的,所以为了保持一致性,我们定义了本地枚举类和本地接口,它们也是隐式静态的。

您现在可以运行以下示例代码以使用在方法中定义的枚举。

private void demoLocalEnum ( )
{
    enum Color { PURPLE, SAFETY_ORANGE }
    System.out.println( Color.PURPLE );
}
Run Code Online (Sandbox Code Playgroud)

在此屏幕截图中,我们可以看到本地枚举如何仅存在于其定义方法中。同级方法无法看到该枚举。尝试从另一个方法调用该枚举会产生错误。

由同级方法尝试调用在其他方法中定义的本地枚举导致的错误的屏幕截图。

查看在IntelliJ 2020.2 IDE 中运行的此类代码演示

含蓄地 static

本地定义的枚举有一个限制:无法访问周围类中的状态。

示例代码:

private void demoLocalEnum ( )
{
    enum Color { PURPLE, SAFETY_ORANGE }
    System.out.println( Color.PURPLE );
}
Run Code Online (Sandbox Code Playgroud)

我的IntelliJ IDE报告错误:

不能从静态上下文中引用非静态变量“x”

正如上面 JEP 395 引用中提到的,本地枚举是隐式的static。因此,您在本地枚举上定义的任何方法都无法访问周围外部类的状态。

引用 JEP 395,关于本地记录,但也适用于本地枚举:

本地记录类是嵌套记录类的一种特殊情况。与嵌套记录类一样,本地记录类是隐式静态的。这意味着它们自己的方法不能访问封闭方法的任何变量;反过来,这避免了捕获一个立即封闭的实例,该实例会默默地向记录类添加状态。本地记录类是隐式静态的事实与本地类相反,本地类不是隐式静态的。事实上,局部类从来都不是静态的——隐式或显式——并且总是可以访问封闭方法中的变量。


emo*_*ory 10

  1. "嵌套的枚举类型是隐式静态的." 8.9枚词

  2. 推断嵌套枚举类型隐式包含静态访问修饰符是合理的.

  3. "如果本地类声明包含以下任何一个访问修饰符,则为编译时错误:public,protected,private或static." 14.3 14.3本地类声明

  • @dhardy我100%同意.我们应该能够在方法中放置枚举和接口.我的回答只是解释了为什么政策禁止本地枚举.我绝对不同意这个政策. (3认同)