我正在做一些实验,无意中写了一段代码,非常奇怪,我完全不理解它。我甚至很惊讶自己居然能编译通过。代码如下:
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
现在我终于要开始问问题了:
Why I don't get any error if I create public method inside the constant and left enumeration empty without this method? In that case, the method I just defined can't be called at all. Or am I wrong?
Update: I know that enumeration can implement interface. However, if I haven't specifically said that, whole code is pointless.
Someone pointed out that even if method can't be accessed from the language in the normal way, it's still possible to use reflection. Well... Why don't we design an inaccessible keyword?
inaccessible void magicalMethod() { // }
Such a method will be compiled into the *.class file. When you want to use it, you've to load bytecode by yourself and interpret it.
I just can't understand, why it's possible to define unreachable method. The only reason I can think is that programmer is working and doesn't have definition of interface yet. So he's just preparing code of single methods and will add "implements" keyword later. Beside this is illogical, it would still require to have such a method in all constants.
I think this should end up with error, not just warning about unused method. You may forget to add "implement" clause or to define method in the enumeration (which would be overridden) and will realize that just after the first use. Java is very strict language, so I'd expect this behavior.
Why I don't get any error if I create public variable (or field, to be more precise) inside the constant? It can't be accessed in the any case (from the outside). Therefore, modifier "public" doesn't make any sense here.
Update: It's more less the same thing as in the previous point, except the visibility modifier is completely useless here. It really doesn't matter if it's public, protected or private, because you won't be able to access that anyway. I think this is a bug.
Why it's possible to define a class (without visibility modifiers), but not interface? Yeah, you wouldn't probably want to write so brutal enumeration that you would need to define classes inside the constant and even to use inheritance there. But if it's possible to define classes and abstract classes, it seems little weird.
Update: This is definitely not something you'd need on regular basis, but I understand that it might be useful. But why it's limited to classes only and interfaces can't be defined as well?
enum Foo { VALUE { class MyClass { // OK } abstract class MyAbstractClass { // OK } interface MyInterface { // FAIL. It won't compile. } } }
Did you use such a functionality somewhere? I can imagine it might be useful, but it's little confusing. Also, when I was searching for some resources about that, I didn't find anything.
Update: I'd like to see some practical example wth overridden methods in an enum constant class body. Have you seen it in some open-source project?
环境:
$ 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)
感谢您的时间和回答!