当前位置: 首页 > 面试题库 >

Java:枚举常量中方法和变量的定义

薛烨
2023-03-14
问题内容

我正在做一些实验,无意间写了一段代码,这很奇怪,我还没完全明白。我什至可以编译它,我什至感到惊讶。看起来像这样:

enum Foo {
    VALUE_1 {
        public int myVariable = 1;
    },
    VALUE_2 {
        public void myMethod() {
            //
        }
    },
    VALUE_3;
}

不出所料,无法通过以下方式访问此类元素:

Foo.VALUE_2.myMethod();

原因是,编译器将在枚举本身内寻找该方法。

我以为不可能从枚举之外访问这些方法和变量。因此,我尝试创建一个参数构造函数,并使用一些内部变量进行调用:

enum Foo {
    VALUE(internalVariable) {
        int internalVariable = 1;
    };

    private Foo(int param) {
        //
    }
}

不可能编译这样的构造。现在,我在想如果没有办法访问常量,那么在常量中定义某些东西有什么意义呢?

我试图在常量本身以及枚举中创建同名方法,以检查其是否以某种方式发生冲突。没有!

enum Foo {
    VALUE_1 {
        int myVariable = 1;

        public int myMethod() {
            return myVariable;
        }
    },
    VALUE_2 {
        //
    };

    public int myMethod() {
        return 0;
    }
}

有趣的时刻到了!我试图在枚举内进行myMethod()的调用,并实际上弄清楚了Java魔术的工作原理。在常量内部定义的方法将覆盖枚举内部定义的方法。

Foo.VALUE_1.myMethod(); // Returns 1
Foo.VALUE_2.myMethod(); // Returns 0

但是,我们不能覆盖变量,对吗?所以我很好奇,它仅适用于变量。

enum Foo {
    VALUE_1 {
        public int myVariable = 1;
    },
    VALUE_2 {
        //
    };

    public int myVariable = 0;
}

....

System.out.println(Foo.VALUE_1.myVariable); // Returns 0
System.out.println(Foo.VALUE_2.myVariable); // Returns 0

现在我终于要问我的问题了:

  1. 如果我在常量中创建 public方法 并没有此方法而将枚举留为空白,为什么没有任何错误?在这种情况下,我刚刚定义的方法 根本无法调用 。还是我错了?

更新: 我知道枚举可以实现接口。但是,如果我没有特别说明,则整个代码毫无意义。

有人指出,即使不能以正常方式从语言中访问方法,仍然可以使用反射。好吧…为什么我们不设计一个 无法访问的 关键字?

    inaccessible void magicalMethod() {
     //
}

这样的方法将被编译到* .class文件中。当您要使用它时,您必须自己加载字节码并对其进行解释。

我只是不明白,为什么可以定义不可达的方法。我能想到的唯一原因是程序员正在工作并且还没有接口的定义。因此,他只是准备单个方法的代码,稍后将添加“
implements”关键字。除了这是不合逻辑的,它仍然需要在所有常量中都使用这种方法。

我认为这应该以错误结尾,而不仅仅是警告未使用的方法。您可能会忘记在枚举中添加“
implement”子句或定义方法(将被覆盖),并且会在首次使用后意识到这一点。Java是非常严格的语言,因此我希望出现这种情况。

  1. 如果在常量内创建 公共变量 (或更精确地说,字段),为什么没有任何错误?在任何情况下(从外部)都无法访问它。因此,修饰符“ public”在这里没有任何意义。

更新:
除了可见性修饰符在这里完全没有用处之外,它与上一点更没有相同之处。它是公共的,受保护的还是私有的都没关系,因为您无论如何都无法访问它。我认为这是一个错误。

  1. 为什么可以 定义一个类 (没有可见性修饰符),但 不能定义接口 呢?是的,您可能不想编写如此残酷的枚举,以至于需要在常量内定义类,甚至在该常量内使用继承。但是,如果可以定义类和抽象类,这似乎并不奇怪。

更新: 绝对不是您定期需要的东西,但是我知道它可能有用。但是为什么它只限于类而接口也不能定义呢?

    enum Foo {
    VALUE {
        class MyClass {
            // OK
        }

        abstract class MyAbstractClass {
            // OK
        }

        interface MyInterface {
            // FAIL. It won't compile.
        }
    }
}
  1. 您在某处使用过这种功能吗?我可以想象它可能有用,但是一点也不令人困惑。另外,当我搜索有关此的一些资源时,我什么也没找到。

更新: 我想在枚举常量类主体中看到一些重写了方法的实际示例。您在某个开源项目中见过吗?

环境:

$ java -version
java version "1.7.0_21"
OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-0ubuntu0.12.10.1)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)

感谢您的时间和回答!


问题答案:

如果我在常量中创建public方法并没有此方法而将枚举留为空白,为什么没有任何错误?在这种情况下,我刚刚定义的方法根本无法调用。还是我错了?

实际上,编译器应该能够看到该方法在枚举常量的类主体之外不可见,并警告您是否未使用该方法-我确信Eclipse会这样做。正如dasblinkenlight指出的那样,这样的公共方法实际上可能是枚举实现的接口所声明的方法的替代。
[…]我刚刚定义的方法根本无法调用。还是我错了?

正确,您错了:Javaenum可以实现接口,如下所示:

interface Bar {
    void myMethod();
}
enum Foo implements Bar {
    VALUE_1 {
        public void myMethod() {
            System.err.println("val1");
        }
    };
}

现在您可以访问myMethodinside了VALUE_1。当然,您将不得不以其他值或enum本身来实现此方法。此外,您始终可以通过反射来访问语言无法访问的方法。

就公共变量而言,似乎反射是这里的唯一方法。尽管如此,没有理由完全禁止此操作(尽管很难想象有一个有用的应用程序可供使用)。

您在某处使用过这种功能吗?

我确实使用了enum实现接口的,每个常量都以其特定方式实现接口的方法。

我只是不明白,为什么可以定义不可达的方法。我能想到的唯一原因是程序员正在工作并且还没有接口的定义。因此,他只是准备单个方法的代码,稍后将添加“
implements”关键字。除了这是不合逻辑的,它仍然需要在所有常量中都使用这种方法。

如前所述,这不适用于枚举常量类。范围很广-私有嵌套类,本地类,匿名类-成员公开是毫无意义的。

这个问题的问题在于只有语言设计师才能真正回答它。我只能给出我的意见,那就是:为什么要出错?语言规范不是免费提供的-
必须精心定义JLS中的所有内容,然后实施和测试。真正的问题是,使它成为错误有什么好处?唯一的事实是,尽管一个未使用的成员可能表示一个错误(因此发出警告),但它没有任何
伤害

如果在常量内创建公共变量(或更精确地说,字段),为什么没有任何错误?在任何情况下(从外部)都无法访问它。因此,修饰符“
public”在这里没有任何意义。

与上面相同-
如果未使用变量,则编译器或至少某些IDE会警告您。这与您publicprivate嵌套类中声明变量然后没有在任何地方引用它相同。在任何情况下,禁止JLS优先考虑禁止这种情况,尽管反射的眼睛可以看到一切。

除了可见性修饰符在这里完全没有用处之外,它与上一点更没有相同之处。它是公共的,受保护的还是私有的都没关系,因为您无论如何都无法访问它。我认为这是一个错误。

在这里,您忘记了成员可能仍会在枚举常量类主体中使用-例如考虑一个辅助方法。只是在这种情况下,访问修饰符无关紧要,可以忽略。

为什么可以定义一个类(没有可见性修饰符),但是不能定义接口呢?是的,您可能不想编写如此残酷的枚举,以至于需要在常量内定义类,甚至在该常量内使用继承。但是,如果可以定义类和抽象类,这似乎并不奇怪。

这是一个很好的问题,我花了一段时间了解您的意思。为了澄清,您是说在这种情况下仅允许该类:

VALUE_1 {
    class Bar { }
    interface Baz { }
},

为了阐明这一点,请尝试上课static

VALUE_1 {
    static class Bar { }
    interface Baz { }
},

现在都不允许。为什么?static枚举常量主体中不能声明任何内容,因为该主体处于该常量 实例 的上下文中。这类似于在内部(非静态嵌套)类的范围内:

class Outer {

    class Inner {
        // nothing static allowed here either!
    }
}

在这种范围内,静态变量,方法,类和 接口 (嵌套时隐式静态)都是禁止的。

您在某处使用过这种功能吗?我可以想象它可能有用,但是一点也不令人困惑。另外,当我搜索有关此的一些资源时,我什么也没找到。

目前尚不清楚您在此指的是什么功能。请更新问题以指定您要查找的内容-枚举常量类主体中的重写方法?田野?辅助方法?助手班?请澄清。



 类似资料:
  • 问题内容: 通过阅读SCJP书籍,我在第1章“自测”中发现了类似的内容: 注意:代码编译正常。我不明白的是为什么我们可以从变量访问DOG,CAT或FISH常量。我认为(并且也写在书中)DOG,FISH,CAT是常量,其实现方式类似于。 所以,如果它们确实是静态的,为什么我们可以从中访问它们呢?最后一行是我熟悉的方式。 问题答案: 写作 和写作一样。也就是说,编译器将用其编译时类型Animal替换变

  • 枚举(enum)是定义一组命名常量的机制,用这种方式定义的常量被称作枚举常量 注:枚举常量的数据类型是整数 使用方法: 下面我们以文本语音转换为例子,说明一下枚举常量的使用方法。 首先我们在窗体上放入语音识别控件,按钮,通用对话框这些基本控件,来制作一个简单的语音文本朗读程序。 1 如果您使用过语音识别控件,就应该知道,使用这个控件的第一步就是先创建它,而创建命令的两个参数就是枚举常量,我们可以看

  • 主要内容:声明常量,实例,VB.Net打印和显示常量,声明枚举,实例常量指的是程序在执行过程中可能不会改变的固定值。 这些固定值也被称为文字。 常量可以是任何基本数据类型,如整数常量,浮点常量,字符常量或字符串文字。 也有枚举常量。 常量的处理方式与常规变量一样,只是它们的值在定义之后无法修改。 枚举是一组命名的整数常量。 声明常量 在VB.Net中,使用语句声明常量。 语句用于模块,类,结构,过程或块级别,以代替文字值。 语句的语法是: 其中, attribut

  • 问题内容: 有什么方法可以在Java枚举声明中定义静态最终变量(有效常量)? 我想要在一个地方定义BAR(1 … n)值的字符串文字值: 对于以上代码,我收到以下错误消息: 在定义字段之前无法引用它 。 问题答案: 正如IntelliJ IDEA建议的那样,在提取常量时-制作静态嵌套类。此方法有效:

  • 问题内容: 我正在查看公司其他部门维护的一些Java代码,顺便说一下,这是一些前C和C ++开发人员所维护的。普遍存在的一件事是使用静态整数常量,例如 除了缺少“最终”限定符外,这种代码也让我有些不安。我本来希望看到的是,从学校开始主要接受Java的培训,这会更像 但是,论点使我失望。为什么要比后者更好呢? 问题答案: 为什么要比后者更好呢? 这样做要好得多,因为它可以为您提供类型安全性并具有自记

  • 问题内容: public enum Operations { 在上面的代码中,两个操作的操作值都会更改。如何有两个具有不同操作类型的Operations.SINGLE实例? 问题答案: 是的,实例是隐式的和。这意味着代码是不明智的。想象两个线程都在调用;您将不会对自己的通话充满信心。 根据Java语言规范的8.9节: 枚举类型(§8.9)不能声明为抽象;这样做会导致编译时错误。 枚举类型是隐式最终