Java:在枚举的常量中定义方法和变量 [英] Java: Definition of methods and variables inside enum's constant

查看:168
本文介绍了Java:在枚举的常量中定义方法和变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一些实验,不小心写了一个代码,这是非常奇怪的,我没有得到这一切。我甚至感到惊讶,我可以编译它。它看起来像这样:

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

如预期的那样,不可能通过以下方式访问这样一个元素:

  Foo.VALUE_2.myMethod(); 

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



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

 枚举Foo {
VALUE(internalVariable){
int internalVariable = 1;
};

private Foo(int param){
//
}
}

不可能编译这样的结构。现在我正在想,如果没有办法访问它,那么在常量中定义一些东西是什么意思。



我正在尝试在常量中创建相同名称的方法在枚举本身,检查它是否以某种方式相撞。它没有!

 枚举Foo {
VALUE_1 {
int myVariable = 1;

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

public int myMethod(){
return 0;
}
}

这里有趣的时刻!我试图在枚举中继续调用myMethod(),实际上弄清了这个Java魔术的工作原理。方法,定义在常量内,覆盖枚举中定义的方法。

  Foo.VALUE_1.myMethod(); //返回1 
Foo.VALUE_2.myMethod(); //返回0

但是,我们不能覆盖变量,对吗?所以我很好奇,它如何与变量一起工作。

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

public int myVariable = 0;
}

....

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

现在我终于得到了我的问题:


  1. 如果我在常量和左边枚举中创建 public方法,没有这种方法,为什么我不会收到任何错误?在这种情况下,我刚刚定义的方法根本不能被调用。或者我错了?



    更新:我知道枚举可以实现界面。但是,如果我没有
    具体说,整个代码是无意义的。



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

     无法访问void magicalMethod(){
    //
    }

    编译成* .class文件。当你想要使用它,你必须自己负载字节码
    并解释它。



    我只是不明白,为什么可以定义不可达的方法。唯一的原因
    我可以想到,程序员正在工作,没有界面的定义。所以
    他只是准备单一方法的代码,并会在稍后添加implements关键字。在
    旁边,这是不合逻辑的,它仍然需要在所有常量中都有这样的方法。



    我认为这应该是错误的,而不仅仅是警告未使用的方法您可能会忘记
    添加实现子句或定义枚举中的方法(这将是
    被覆盖),并将在第一次使用之后实现。 Java是非常严格的语言,
    所以我希望这个行为。


  2. 为什么我创建公共变量(或字段,要更精确)里面的常数?在任何情况下都不能访问(从外部)。因此,修改者public在这里没有任何意义。



    更新:它与以前的观点相同,除了可见性
    修饰符在这里完全没用。如果它是公开的,保护
    或私有的,这并不重要,因为你无法访问。我认为这是一个错误。


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



    更新:这绝对不是你需要的但是我理解
    它可能是有用的。但是为什么它只限于类,界面也不能被定义为

     枚举Foo {
    VALUE {
    class MyClass {
    // OK
    }

    抽象类MyAbstractClass {
    // OK
    }

    接口MyInterface {
    // FAIL。它不会编译。
    }
    }
    }


  4. 这样的功能在哪里?我可以想象它可能是有用的,但它很少混淆。另外,当我正在搜索一些资源时,我没有找到任何东西。



    更新:我想看到一些一个枚举常量类体的实例。你有没有在一些开源项目中看到它?


环境:

  $ java -version 
java版本1.7.0_21
OpenJDK运行时环境(IcedTea 2.3.9)( 7u21-2.3.9-0ubuntu0.12.10.1)
OpenJDK 64位服务器虚拟机(构建23.7-b01,混合模式)

感谢您的时间和您的回答!

解决方案


为什么我没有得到任何错误,如果我创建公共方法里面的常量和左枚举空没有这种方法?在这种情况下,我刚刚定义的方法根本无法调用。或者我错了?


实际上,编译器应该能够看到该方法在枚举常量的类体之外是不可见的并警告您是否不使用 - 我确定Eclipse确实这样做。作为dasblinkenlight 指出,这样的公共方法实际上可能是覆盖由枚举实现的接口声明的方法


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


正如我已经指出的,特别适用于枚举常数类。有很多范围 - 私人嵌套类,本地类,匿名类 - 成员公开是无意义的。



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


为什么我在常量内创建公共变量(或字段,更准确)时不会收到任何错误?在任何情况下都不能访问(从外部)。因此,修改器public在这里没有任何意义。


与上述相同 - 编译器或至少一些IDE将发出警告你如果不使用变量。这与在 private 嵌套类中声明一个 public 变量一样,然后没有在任何地方引用它。在任何情况下,尽管反思的眼睛全都看不到JLS的优先地位,但不是JLS的优先考虑。


它更少与前一点相同的事情,除了可见性修饰符在这里完全没用。如果它是公共的,受保护的或私有的,这并不重要,因为你无法访问。我认为这是一个错误。


在这里,你忘记了成员可能仍然在枚举常数班体内使用 - 的帮助方法。只是在这种情况下,访问修饰符根本无关紧要,可以被关闭。


为什么可以定义一个类可见度修饰符),但不是界面?是的,你不会想写这么残酷的枚举,你需要在常量中定义类,甚至在那里使用继承。但是如果可以定义类和抽象类,这似乎并不奇怪。


这是一个很好的问题,它需要我一个而要明白你的意思。澄清一点,你说在这种情况下,只允许上课:

  VALUE_1 {
class Bar { }
接口Baz {}
},

尝试制作课程 static

  VALUE_1 {
static class Bar {}
接口Baz {}
},

允许。为什么?没有什么 static 可以在枚举常量体中声明,因为正文位于该常量的实例的上下文中。这类似于内部(非静态嵌套)类的范围:

  class Outer {

class Inner {
//这里没有任何静态允许!
}
}

静态变量,方法,类和


在某个地方使用了这样的功能,(嵌套时是隐式静态的) ?我可以想象它可能是有用的,但它很少混淆。此外,当我正在搜索一些资源时,我没有找到任何东西。


目前还不清楚你所指的是什么功能这里。请更新问题以指定您正在寻找什么 - 在枚举常量类体中重写方法?场?助手方法?助手班?请澄清。


I was doing some experiments and accidently wrote a code, which is very weird and I don't get it all. I was even surprised that I can compile it. It looks like this:

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

As expected, it's not possible to access such an element in the following way:

Foo.VALUE_2.myMethod();

The reason is, that compiler will look for that method inside the enumeration itself.

I presumed that it's not possible to access these methods and variables from outside the enumeration. For this reason, I tried to create a parametric constructor and call it with some internal variable:

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

    private Foo(int param) {
        //
    }
}

It wasn't possible to compile such a construction. Now I was thinking what's the point of defining something inside the constant if there is no way to access it.

I was trying to create the same-named methods in the constant as well in the enumeration itself to check out if it collides in some way. It didn't!

enum Foo {
    VALUE_1 {
        int myVariable = 1;

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

    public int myMethod() {
        return 0;
    }
}

And here comes the funny moment! I tried to proceed call of myMethod() inside the enumeration and actually figured out how this Java magic works. Methods, which are defined inside the constant, overrides methods defined inside the enumeration.

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

However, we can't override variable, right? So I was curious, how it works with variables only.

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

Now I'm finally getting to my questions:

  1. 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.

  2. 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.

  3. 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.
            }
        }
    }
    

  4. 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?

Environment:

$ 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)

Thanks for your time and for your answers!

解决方案

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?

In fact the compiler should be able to see that the method isn't visible outside the enum constant's class body and warn you if it isn't used - I know for sure that Eclipse does this. As dasblinkenlight points out, such a public method may in fact be an override of a method declared by an interface that the enum implements.

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.

As I already noted, this doesn't specifically apply to enum constant classes. There are many scopes - private nested classes, local classes, anonymous classes - where it's pointless for a member to be public.

The problem with this question is that only the language designers could truly answer it. I can only give my opinion, which is: why should it be an error? The language spec doesn't come for free - everything in the JLS must be painstakingly defined, and then implemented and tested. The real question is, what benefit is there to making it an error? The mere fact is that while an unused member might indicate a bug (hence the warning), it isn't hurting anything.

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.

Same as above - the compiler or at least some IDEs will warn you if a variable isn't used. This is the same as if you declared a public variable in a private nested class and then didn't reference it anywhere. In any case, it's not the priority of the JLS to forbid such situations, notwithstanding that the eye of reflection sees all.

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.

Here, you're forgetting that members might still be used within the enum constant class body - think of a helper method for example. It's just that in this case access modifiers simply don't matter and can be left off.

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.

This is a good question, and it took me a while to understand what you mean. To clarify, you're saying that in this situation only the class is allowed:

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

To shed light on this, try making the class static:

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

Now neither are allowed. Why? Nothing static can be declared in an enum constant body, because the body is in the context of the instance of that constant. This is similar to being in the scope of an inner (non-static nested) class:

class Outer {

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

Static variables, methods, classes, and interfaces (which are implicitly static when nested) are all forbidden in such a scope.

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.

It's unclear what functionality specifically your referring to here. Please update the question to specify what exactly you're looking for - overridden methods in an enum constant class body? Fields? Helper methods? Helper classes? Please clarify.

这篇关于Java:在枚举的常量中定义方法和变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆