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

发布于 2024-07-16 07:22:04 字数 569 浏览 5 评论 0 原文

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

public class LocalEnums {

    public LocalEnums() {
    }

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

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

    }
}

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

成员枚举 LocalEnum 不能是 本地

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

我发现这在某些情况下非常有用。 在我正在工作的情况下,其余代码不需要了解有关enum的任何信息。

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

Today, I found myself coding something like this ...

public class LocalEnums {

    public LocalEnums() {
    }

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

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

    }
}

and I was kind of surprised when the compiler reported an error on the local enum:

The member enum LocalEnum cannot be
local

Why can't enums be declared local like classes?

I found this very useful in certain situations. In the case I was working, the rest of the code didn't need to know anything about the enum.

Is there any structural/design conflict that explains why this is not possible or could this be a future feature of Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

桃扇骨 2024-07-23 07:22:04

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

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

作为评论:如果您的方法足够大以至于它们需要自己的枚举,那么这是您需要重构的强烈信号。

Enums are static nested classes because they define static member variables (the enum values), and this is disallowed for inner classes: http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.1.3

Update: I was looking through the JLS (java language specification) for more detail on the restrictions of static nested classes, and didn't find it (although it's probably there, hidden under a different topic). From a pure implementation perspective, there's no reason that this couldn't be done. So I suspect that it was a language philosophy issue: it shouldn't be done, therefore won't be supported. But I wasn't there, so that's pure speculation.

As a comment: if your methods are large enough that they require their own enums, then it's a strong sign that you need refactoring.

可是我不能没有你 2024-07-23 07:22:04

从 Java 16(2021-03 发布)和 Java 17(2021-09 发布)开始,其他答案已过时。

Java 16+ 中的本地枚举

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

引用 JEP 395:

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

...

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

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

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

private void demoLocalEnum ( )
{
    enum Color { PURPLE, SAFETY_ORANGE }
    System.out.println( Color.PURPLE );
}

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

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

请参阅IntelliJ 中运行此类代码的演示 2020.2 IDE

隐式静态

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

示例代码:

private void demoLocalEnum ()
{
    int x = 42;

    enum Color
    {
        PURPLE,
        SAFETY_ORANGE;

        public void demo ()
        {
            System.out.println( "Now is " + Instant.now() );  // This line works.
            System.out.println( "x = " + x );  // ERROR — Non-static variable 'x' cannot be referenced from a static context.
        }
    }

    Color.PURPLE.demo();
}

我的 IntelliJ IDE 报告错误:

无法从静态上下文引用非静态变量“x”

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

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

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

Other Answers are outmoded as of Java 16 (released 2021-03) and Java 17 (released 2021-09).

Local enums in Java 16+

As part of the records feature introduced in Java 16, enums may now be defined locally. Indeed, records, enums, and interfaces can all be local now.

To quote JEP 395:

The ability to declare local record classes, local enum classes, and local interfaces was introduced.

The addition of local record classes is an opportunity to add other kinds of implicitly-static local declarations.

Nested enum classes and nested interfaces are already implicitly static, so for consistency we define local enum classes and local interfaces, which are also implicitly static.

You can now run the following example code to use an enum defined within a method.

private void demoLocalEnum ( )
{
    enum Color { PURPLE, SAFETY_ORANGE }
    System.out.println( Color.PURPLE );
}

In this screenshot, we can see how the local enum exists only within its defining method. A sibling method cannot see that enum. Trying to call that enum from another method generates an error.

Screenshot of an error caused by a sibling method trying to call a local enum defined in some other method.

See a demo of such code running in the IntelliJ 2020.2 IDE.

Implicitly static

There is one limitation with a locally defined enum: No access to state in surrounding class.

Example code:

private void demoLocalEnum ()
{
    int x = 42;

    enum Color
    {
        PURPLE,
        SAFETY_ORANGE;

        public void demo ()
        {
            System.out.println( "Now is " + Instant.now() );  // This line works.
            System.out.println( "x = " + x );  // ERROR — Non-static variable 'x' cannot be referenced from a static context.
        }
    }

    Color.PURPLE.demo();
}

My IntelliJ IDE reports error:

Non-static variable 'x' cannot be referenced from a static context

As mentioned in the JEP 395 quote above, a local enum is implicitly static. So any methods you may define on your local enum cannot access state on the surrounding outer class.

To quote JEP 395, regarding local records but applying to local enums as well:

Local record classes are a particular case of nested record classes. Like nested record classes, local record classes are implicitly static. This means that their own methods cannot access any variables of the enclosing method; in turn, this avoids capturing an immediately enclosing instance which would silently add state to the record class. The fact that local record classes are implicitly static is in contrast to local classes, which are not implicitly static. In fact, local classes are never static — implicitly or explicitly — and can always access variables in the enclosing method.

千と千尋 2024-07-23 07:22:04

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

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

    public void foo()
    {
    }
}

我认为我真的不想读取在其中声明新类型的方法 - 您是否有任何具体原因想要在其中声明它方法而不是仅仅作为嵌套类型? 我可以看到“没有其他方法需要知道”的论点,但我认为注释可以解决这个问题,并且仍然留下更多可读的代码。

I rarely find myself writing any types within a method, unless it's an anonymous inner class. You can, however, write nested enums:

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

    public void foo()
    {
    }
}

I don't think I'd really want to read a method which declared a new type within it - do you have any concrete reason for wanting to declare it inside the method instead of just as a nested type? I can see the "no other methods need to know" argument, but I think a comment can sort that out and still leave more readable code.

药祭#氼 2024-07-23 07:22:04
  1. “嵌套枚举类型是隐式的
    静态。” 8.9 枚举

  2. 它可以合理地推断
    嵌套枚举类型隐式包含
    静态访问修饰符。

  3. “如果
    局部类声明包含任何
    以下访问之一
    修饰符:公共、受保护、
    私有或静态。"14.3 14.3 本地
    类声明
  1. "Nested enum types are implicitly
    static." 8.9 Enums

  2. It is reasonable to infer that
    nested enum types implicitly contain
    the static access modifier.

  3. "It is a compile-time error if a
    local class declaration contains any
    one of the following access
    modifiers: public, protected,
    private, or static."14.3 14.3 Local
    Class Declarations
ま昔日黯然 2024-07-23 07:22:04

这很奇怪,因为java内部类定义说编译时常量可以声明为静态,并且Enum的成员显然是编译时常量,加上枚举是静态类,据说......

文档

8.1.3 内部类和封闭实例

(...) 内部类不能声明静态成员,除非它们是编译时常量字段。

class Outer{
    class Inner extends HasStatic{
        static final int x = 3;         // ok - compile-time constant
        static int y = 4;           // compile-time error, an inner class
    }
    static class NestedButNotInner{
        static int z = 5;           // ok, not an inner class
    }
    interface NeverInner{}              // interfaces are never inner
}

It's weird because the java inner class definition says that compile-time constants can be declared static, and a member of a Enum is clearly compile-time constant, plus enum is a static class, suposedly...

Documentation:

8.1.3 Inner Classes and Enclosing Instances

(...) Inner classes may not declare static members, unless they are compile-time constant fields.

class Outer{
    class Inner extends HasStatic{
        static final int x = 3;         // ok - compile-time constant
        static int y = 4;           // compile-time error, an inner class
    }
    static class NestedButNotInner{
        static int z = 5;           // ok, not an inner class
    }
    interface NeverInner{}              // interfaces are never inner
}
离不开的别离 2024-07-23 07:22:04

http://mindprod.com/jgloss/enum.html 给出了 Java 枚举的良好描述- 如前所述,枚举被定义为静态,因此不能将它们声明为局部变量

http://mindprod.com/jgloss/enum.html gives a good description of java enums - as previously mentioned, enums are defined as static so they can't be declared as locals

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文