This question already has an answer here:
The task is to implement beautiful strategy design pattern with the java enum:
public enum MyEnum {
FIRST {
@Override
public String doIt() {
return "1: " + someField; //error
}
},
SECOND {
@Override
public String doIt() {
return "2: " + someField; //error
}
};
private String someField;
public abstract String doIt();
}
but when referring to someField I get
Cannot make a static reference to the non-static field someField.
What is wrong and is it possible to do that better?
A specialized enum is nothing but a subclass with inner-class semantics. If you look at the byte code after compilation, you will notice that the compiler only inserts accessor method for reading a private field but any specialized enum is compiled as its own class. You can think about your enum as being implemented as:
public abstract class MyEnum {
private static class First extends MyEnum {
@Override
public String doIt() {
return "1: " + someField; //error
}
}
private static class Second extends MyEnum {
@Override
public String doIt() {
return "2: " + someField; //error
}
}
public static final MyEnum FIRST = new First();
public static final MyEnum SECOND = new Second();
private String someField;
public abstract String doIt();
}
As you can see, the same compiler errors occur. Effectively, your problem does not relate to enums but to their inner-class semantics.
However, you found a borderline case of the compiler guessing the intend of your code and trying to warn you that what you intend is illegal. In general, the someField field is visible to any specialized enum. However, there are two ways of accessing the private field from an inner class and only one is legal:
privatemembers are not inherited. You can therefore not access aprivatefield fromthisinstance when it was defined in a super class.For inner classes, members of outer classes are accessible even if they are
private. This is achieved by the compiler by inserting accessor methods to the outer classes which expose theprivatefields by accessor methods. A non-staticfield can only be accessed if the inner class is non-static. Forenums, the inner classes are however alwaysstatic.
The later condition is what the compiler complains about:
Cannot make a static reference to the non-static field
someField
You are trying to access a non-static field from a static inner class. This is not possible even though the field would be technically visible because of the inner class semantics. You could instruct the compiler explicitly to access the value by reading it from the super class by for example:
public String doIt() {
MyEnum thiz = this;
return thiz.someField;
}
Now the compiler knows that you are trying to access a member of a visible (outer) type instead of erroneously accessing the someField field of the (non-static) outer class instance (which does not exist). (Similarly, you could write super.someField which expresses the same idea that you want to go down the inheritance chain and not access an outer instance's field.) The easier solution would however be to simply make the field protected. This way the compiler is happy about the inheritance visibility and compiles your original setup.
If you make someField protected instead of private or use super.someField instead you will be able to access it.
someField is private, remove the private modifier or move it into your abstract classes.
Private fields are not accessible from subclasses which is exactly what you do when you implement the MyEnum.doIt() abstract method on a per-instance basis. Change it to protected, and it will work.
someField is a private variable when enums are static variables. You cant assign non static variable to static variable in this way.
Apparently the problem is that when you say:
public enum MyEnum {
...
public abstract String doIt();
}
It implicitly needs the enum to be an abstract "class", as you must provide an implementation for it. Therefore, when you say
FIRST {
@Override
public String doIt() {
return "1: " + this.someField; //error
}
}
It gives an error because you are trying to access the "base class" MyEnum's private field, and as it is private, it is not visible from the implicitly created anonymous subclass. As such, protected is visible from the subclass, therefore it fixes the problem.
There are some questions on Stack Overflow that talk about this problem, such as Singletons, Enums and anonymous inner classes or Why can I anonymously subclass an enum but not a final class? .
EDIT: Apparently not everything in this statement is correct, because while this.someField doesn't work as the field is not visible from the subclass, it is visible accessed as super.someField. This is a phenomenon I've not seen before, and will try to look into now.
What you could do is the following:
public enum MyEnum {
FIRST,SECOND;
private String someField;
public String doIt(){
switch(this){
case FIRST: return "1: " + someField; break;
case SECOND: return "2: " + someField; break;
}
}
}
This way, you still inherit Enum and you can use MyEnum.values() and other perks that come from deriving Enum.
I wouldn't implement Strategy pattern using an enumeration. All code ends up in the same unti (file).
The idea is to separate the code. Use an interface as base class and then implement each Strategy as a separate sub-class. Nice a clean.
来源:https://stackoverflow.com/questions/25010763/how-to-use-fields-in-java-enum-by-overriding-the-method