Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:枚举'内方法和变量的定义;s常数_Java_Oop_Inheritance_Enums_Language Design - Fatal编程技术网

Java:枚举'内方法和变量的定义;s常数

Java:枚举'内方法和变量的定义;s常数,java,oop,inheritance,enums,language-design,Java,Oop,Inheritance,Enums,Language Design,我在做一些实验,不小心写了一个代码,这很奇怪,我不完全明白。我甚至惊讶于我能编译它。看起来是这样的: enum Foo { VALUE_1 { public int myVariable = 1; }, VALUE_2 { public void myMethod() { // } }, VALUE_3; } interface Bar { void myMethod();

我在做一些实验,不小心写了一个代码,这很奇怪,我不完全明白。我甚至惊讶于我能编译它。看起来是这样的:

enum Foo {
    VALUE_1 {
        public int myVariable = 1;
    },
    VALUE_2 {
        public void myMethod() {
            //
        }
    },
    VALUE_3;
}
interface Bar {
    void myMethod();
}
enum Foo implements Bar {
    VALUE_1 {
        public void myMethod() {
            System.err.println("val1");
        }
    };
}
private SoundPack soundPack = SoundPack.CLASSICAL;
正如预期的那样,无法通过以下方式访问此类元素:

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
现在我终于开始回答我的问题了:

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

    更新:我知道枚举可以实现接口。然而,如果我没有 具体来说,整个代码是毫无意义的

    有人指出,即使在正常情况下无法从语言访问该方法 这样,仍然可以使用反射。好。。。我们为什么不设计一个不可访问的 关键词

    这种方法将被编译到*.class文件中。当你想使用它时,你必须 自己加载字节码并解释它

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

    我认为这应该以错误结束,而不仅仅是警告未使用的方法。你可能会忘记 在枚举中添加“implement”子句或定义方法 并将在首次使用后意识到这一点。Java是非常严格的语言, 所以我期待这种行为

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

    更新:除了可见性之外,与上一点几乎没有什么不同 修饰符在这里是完全无用的。这真的不重要,如果它是公开的,受保护的 或者是私人的,因为你无论如何都无法访问它。我认为这是一个错误

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

    更新:这绝对不是你经常需要的东西,但我理解 这可能是有用的。但是为什么它只限于类,而接口不能 也有定义吗

    enum Foo {
        VALUE {
            class MyClass {
                // OK
            }
    
            abstract class MyAbstractClass {
                // OK
            }
    
            interface MyInterface {
                // FAIL. It won't compile.
            }
        }
    }
    
  • 你在什么地方使用过这样的功能吗?我可以想象它可能有用,但有点让人困惑。另外,当我在搜索有关这方面的资源时,我什么也没找到

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

  • 环境:

    $ 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)
    
    谢谢你的时间和回答

    枚举常量的可选类主体隐式定义 匿名类声明(§15.9.5),立即扩展 封闭枚举类型

    创造这样的东西

    VALUE_2 {
        public void myMethod() {
            //
        }
    },
    
    当枚举本身(或其超类型)中没有声明
    myMethod()
    时,只会将方法的作用域设置为抽象类,即不能在该主体之外调用。类似的行为也适用于此主体内声明的字段。
    public
    标识符不会改变任何内容

    编辑

    对于第三个问题,因为您正在声明一个匿名类,所以没有其他组件可以访问(实现)接口。另一方面,类提供行为,因此可以在匿名类中使用

    查看一些匿名类

    结束编辑

    至于4。我在实践中从未见过这样的代码。如果希望某个助手方法执行仅与该特定枚举相关的特定行为,则该方法非常有用。这将是非常奇怪的,可能更适合一个真正的类

    请看下面的图片。您可能希望有许多单例,每个单例都有自己的实现。使用重写方法的匿名枚举类声明可以实现这一点

    […]我刚才定义的方法根本无法调用。还是我错了

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

    enum Foo {
        VALUE_1 {
            public int myVariable = 1;
        },
        VALUE_2 {
            public void myMethod() {
                //
            }
        },
        VALUE_3;
    }
    
    interface Bar {
        void myMethod();
    }
    enum Foo implements Bar {
        VALUE_1 {
            public void myMethod() {
                System.err.println("val1");
            }
        };
    }
    
    private SoundPack soundPack = SoundPack.CLASSICAL;
    
    现在您可以访问
    myMethod
    内部的
    VALUE\u 1
    。当然,您将被迫实施
    public enum SoundPack {
        CLASSICAL {
            @Override
            public String getSoundPickUp() {
                return "res/sounds/classical/pick.wav";
            }
    
            @Override
            public String getSoundNewLevel() {
                return "res/sounds/classical/success.wav";
            }
    
            @Override
            public String getSoundFail() {
                return "res/sounds/fail.wav";
            }
        },
        UNHEALTHY {
            @Override
            public String getSoundPickUp() {
                return "res/sounds/unhealthy/quick_fart.wav";
            }
    
            @Override
            public String getSoundNewLevel() {
                return "res/sounds/unhealthy/toilet_flush.wav";
            }
    
            @Override
            public String getSoundFail() {
                return "res/sounds/unhealthy/vomiting.wav";
            }
        };
    
        public abstract String getSoundPickUp();
        public abstract String getSoundNewLevel();
        public abstract String getSoundFail();
    }
    
    private SoundPack soundPack = SoundPack.CLASSICAL;
    
    configuration.getSoundPack().getSoundNewLevel();