tzi*_*ima 9 java oop inheritance enums language-design
我正在做一些实验并且意外地编写了一个代码,这非常奇怪而且我不能完全理解.我甚至感到惊讶,我可以编译它.它看起来像这样:
enum Foo {
VALUE_1 {
public int myVariable = 1;
},
VALUE_2 {
public void myMethod() {
//
}
},
VALUE_3;
}
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,不可能通过以下方式访问这样的元素:
Foo.VALUE_2.myMethod();
Run Code Online (Sandbox Code Playgroud)
原因是,编译器将在枚举本身内查找该方法.
我假设不可能从枚举之外访问这些方法和变量.出于这个原因,我尝试创建一个参数化构造函数并使用一些内部变量调用它:
enum Foo {
VALUE(internalVariable) {
int internalVariable = 1;
};
private Foo(int param) {
//
}
}
Run Code Online (Sandbox Code Playgroud)
编译这样的结构是不可能的.现在我在想如果没有办法访问它,在常量中定义一些内容是什么意思.
我试图在常量中创建同名的方法以及枚举本身,以检查它是否以某种方式发生碰撞.它没有!
enum Foo {
VALUE_1 {
int myVariable = 1;
public int myMethod() {
return myVariable;
}
},
VALUE_2 {
//
};
public int myMethod() {
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
这是有趣的时刻!我试图在枚举中继续调用myMethod()并实际找出这个Java魔法是如何工作的.方法,在常量内定义,覆盖枚举中定义的方法.
Foo.VALUE_1.myMethod(); // Returns 1
Foo.VALUE_2.myMethod(); // Returns 0
Run Code Online (Sandbox Code Playgroud)
但是,我们无法覆盖变量,对吧?所以我很好奇,它只适用于变量.
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
Run Code Online (Sandbox Code Playgroud)
现在我终于回答了我的问题:
如果我在常量和左枚举中创建公共方法而没有此方法,为什么我没有收到任何错误?在那种情况下,我刚刚定义的方法根本无法调用.还是我错了?
更新:我知道枚举可以实现接口.但是,如果我没有具体说明,整个代码是没有意义的.
有人指出,即使无法以正常方式从语言中访问方法,仍然可以使用反射.那么......为什么我们不设计一个无法访问的 关键字?
inaccessible void magicalMethod() {
//
}
Run Code Online (Sandbox Code Playgroud)
这样的方法将被编译到*.class文件中.当你想要使用它时,你必须自己加载字节码并解释它.
我无法理解,为什么可以定义无法访问的方法.我能想到的唯一原因是程序员正在工作,还没有接口的定义.所以他只是准备单个方法的代码,稍后会添加"implements"关键字.除此之外是不合逻辑的,它仍然需要在所有常量中都有这样的方法.
我认为这应该最终导致错误,而不仅仅是警告未使用的方法.您可能忘记添加"implements"子句或在枚举中定义方法(将被覆盖)并在第一次使用之后实现.Java是非常严格的语言,所以我期待这种行为.
如果我在常量中创建公共变量(或更精确的字段),为什么我不会收到任何错误?在任何情况下(从外部)都无法访问它.因此,修饰语"public"在这里没有任何意义.
更新:除了可见性修饰符在这里完全没用之外,它与上一点相同.它是公共的,受保护的还是私有的并不重要,因为无论如何你都无法访问它.我认为这是一个错误.
为什么可以定义一个类(没有可见性修饰符),但不能定义接口?是的,你可能不想编写如此残酷的枚举,你需要在常量中定义类,甚至在那里使用继承.但是,如果可以定义类和抽象类,那似乎有点奇怪.
更新:这绝对不是您经常需要的东西,但我知道它可能有用.但为什么它仅限于类,接口也不能定义?
enum Foo {
VALUE {
class MyClass {
// OK
}
abstract class MyAbstractClass {
// OK
}
interface MyInterface {
// FAIL. It won't compile.
}
}
}
Run Code Online (Sandbox Code Playgroud)你在某个地方使用过这样的功能吗?我可以想象它可能有用,但它有点令人困惑.此外,当我在寻找一些资源时,我没有找到任何东西.
更新:我想在枚举常量类体中看到一些重写方法的实际示例.你有没有在一些开源项目中看到它?
环境:
$ 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)
Run Code Online (Sandbox Code Playgroud)
感谢您的时间和答案!
如果我在常量内创建公共方法并将枚举保留为空而没有此方法,为什么我不会收到任何错误?这样的话,我刚才定义的方法就根本无法被调用了。还是我错了?
事实上,编译器应该能够看到该方法在枚举常量的类主体之外不可见,并在未使用该方法时向您发出警告 - 我确信 Eclipse 会这样做。正如 dasblinkenlight指出的那样,这样的公共方法实际上可能是对枚举实现的接口声明的方法的重写。
我只是不明白,为什么可以定义无法访问的方法。我能想到的唯一原因是程序员正在工作并且还没有接口的定义。所以他只是准备单一方法的代码,稍后会添加“implements”关键字。除此之外,这是不合逻辑的,它仍然需要在所有常量中都有这样的方法。
正如我已经指出的,这并不特别适用于枚举常量类。有许多作用域——私有嵌套类、本地类、匿名类——在这些作用域中,成员是公共的是没有意义的。
这个问题的问题在于,只有语言设计者才能真正回答它。我只能给出我的看法,那就是:为什么会是错误呢?语言规范不是免费的 - JLS 中的所有内容都必须精心定义,然后实施和测试。真正的问题是,犯错误有什么好处?事实是,虽然未使用的成员可能表明存在错误(因此出现警告),但它不会造成任何损害。
如果我在常量内创建公共变量(或更准确地说是字段),为什么我不会收到任何错误?无论如何(从外部)都无法访问它。因此,修饰语“public”在这里没有任何意义。
与上面相同 - 如果未使用变量,编译器或至少某些 IDE 会警告您。public这与您在private嵌套类中声明变量但没有在任何地方引用它的情况相同。无论如何,JLS 的首要任务并不是禁止此类情况,尽管反思之眼能洞察一切。
它与上一点不太一样,只是可见性修饰符在这里完全没用。它是公共的、受保护的还是私有的并不重要,因为无论如何你都无法访问它。我认为这是一个错误。
在这里,您忘记了成员可能仍然在枚举常量类主体中使用 - 例如,考虑一个辅助方法。只是在这种情况下,访问修饰符根本不重要,可以省略。
为什么可以定义类(没有可见性修饰符),但不能定义接口?是的,您可能不想编写如此残酷的枚举,以至于您需要在常量中定义类,甚至在那里使用继承。但如果可以定义类和抽象类,那就没什么奇怪的了。
这是个好问题,我花了一段时间才明白你的意思。为了澄清,你是说在这种情况下只允许班级:
VALUE_1 {
class Bar { }
interface Baz { }
},
Run Code Online (Sandbox Code Playgroud)
为了阐明这一点,请尝试制作课程static:
VALUE_1 {
static class Bar { }
interface Baz { }
},
Run Code Online (Sandbox Code Playgroud)
现在两者都不允许。为什么?static枚举常量主体中不能声明任何内容,因为主体位于该常量实例的上下文中。这类似于处于内部(非静态嵌套)类的范围内:
class Outer {
class Inner {
// nothing static allowed here either!
}
}
Run Code Online (Sandbox Code Playgroud)
静态变量、方法、类和接口(嵌套时隐式静态)都禁止出现在这样的范围内。
您在某处使用过这样的功能吗?我可以想象它可能有用,但有点令人困惑。另外,当我搜索相关资源时,我没有找到任何内容。
目前尚不清楚您在这里具体指的是什么功能。请更新问题以指定您到底在寻找什么 - 枚举常量类主体中的重写方法?字段?辅助方法?辅助类?请澄清。
| 归档时间: |
|
| 查看次数: |
5778 次 |
| 最近记录: |