I am designing a text-only videogame with two characters not often seen together, yet very much alike in heart and disposition.
My problem is that I don't know how to initialise an enum constant through a constructor using a static final inner constant. Otherwise the game is good to go. ;)
Here's the dilemma:
The enum constants must be defined in the first line of the enum, if I am not mistaken
The first line can't refer to anything coming after it (i.e. "cannot reference a field before it is defined")
How do I resolve this catch-22?
Here some sample code released from the game under non-disclosure agreement:
enum ValiantHeroWithPrincessSavingTendencies {
SUPERMARIO(TYPICAL_QUOTE_FROM_MARIO), ZELDA(TYPICAL_QUOTE_FROM_ZELDA);
private String aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
public String getQuoteUnderStressfulCircumstances() {
return aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
}
private ValiantHeroWithPrincessSavingTendencies(String quote) {
aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive = quote;
}
private static final String TYPICAL_QUOTE_FROM_ZELDA = "Have at ya!";
private static final String TYPICAL_QUOTE_FROM_MARIO = "We, wagliu'!";
}
I am trying to initialise SUPERMARIO using TYPICAL_QUOTE_FROM_MARIO but I haven't defined TYPICAL_QUOTE_FROM_MARIO yet. Moving the private static final field before SUPERMARIO is illegal, I think.
The only viable options are to either a) move your constants to another class or b) just put your constants directly into the value initializers.
If you move your constants, you can make the class a static class in the enum:
enum ValiantHeroWithPrincessSavingTendencies {
SUPERMARIO(Quotes.TYPICAL_QUOTE_FROM_MARIO),
ZELDA(Quotes.TYPICAL_QUOTE_FROM_ZELDA);
private String aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
public String getQuoteUnderStressfulCircumstances() {
return aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
}
private ValiantHeroWithPrincessSavingTendencies(String quote) {
aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive = quote;
}
private static class Quotes {
private static final String TYPICAL_QUOTE_FROM_ZELDA = "Have at ya!";
private static final String TYPICAL_QUOTE_FROM_MARIO = "We, wagliu'!";
}
}
You can just access them via class name:
enum ValiantHeroWithPrincessSavingTendencies {
SUPERMARIO(ValiantHeroWithPrincessSavingTendencies.TYPICAL_QUOTE_FROM_MARIO),
ZELDA(ValiantHeroWithPrincessSavingTendencies.TYPICAL_QUOTE_FROM_ZELDA);
...
private static final String TYPICAL_QUOTE_FROM_ZELDA = "Have at ya!";
private static final String TYPICAL_QUOTE_FROM_MARIO = "We, wagliu'!";
}
It's simplier than Brian's solution
The private static final constants are local to the enum; just code them in the instance definitions. After that point they can be accessed internally from the aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive variable.
You could always do something hacky like this:
public enum Derp
{
SOMETHING(),
SOMETHINGELSE();
private String herp;
public static final String A = "derp", B = "derp2";
public String getHerp()
{
return herp;
}
static
{
SOMETHING.herp = A;
SOMETHINGELSE.herp = B;
}
}
Related
I must define a class which all it does is hold constants.
public static final String CODE1 = "100";
public static final String CODE2 = "200";
Now I want use these values in other classes. Is it better to use this class as a static class or instantiate it ?
Thanks.
Note : I know enums but in this context, I must use a class.
Just to use the values, you certainly shouldn't instantiate the class. Just because you can access static members as if they were instance members doesn't mean it's a good idea.
If the class really only contains constants - and if you're sure that's a good idea, rather than those constants appearing within classes which are directly related to them - you should make it a final class with a private constructor, so that no-one can pointlessly instantiate it:
public final class Codes {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
// Prevent instantiation
private Codes() {
}
}
Don's answer suggesting using an enum is a very good idea too - it means you can use Code in your API everywhere that you don't need the exact string representation, which prevents you from accidentally using non-code values.
Jons answer is correct, although I want to show you a solution with an enum.
There is a disadvantage in accessing its String value as you have to call Code.CODE1.text() instead of Code.CODE1.
public enum Code {
CODE1("100"), CODE2("200");
private String text;
Codes(String text) {
this.text = text;
}
public String text() {
return text;
}
}
java language spec and JVM spec allow you to do anything you wanted, whether instantiate a class or use final or use other way....
Just use Eclipse and try !
while there is some good practice, Jon Skeet's answer is one good practice.
Java Language is not support global variable
public class ComonFun {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
public static String CODE1(){
return CODE1;
}
public static String CODE2(){
return CODE2;
}
}
implement
public class Main {
public static void main(String[] args) {
System.out.println(ComonFun.CODE1());
System.out.println(ComonFun.CODE2());
}
}
i think that you need simply to declare an interface, you won't need to specify the clause "public static final". and it can be usuable throgh the hall project.
Use them as static, don't go for instantiation.
Even use static import as a benefit.
package coma;
import static coma.ImportStatments.*;
public class UsingClass {
public static void main(String[] args) {
System.out.println(CODE1);
}
}
And the class with final variables would look like this:
package coma;
public class ImportStatments {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
}
I want to create an enum and declare several constants inside of it for inner usage...
public enum SearchType {
static final String TEXT = "text";
static final String BOOLEAN = "boolean";
STARTS_WITH(TEXT),
ENDS_WITH(TEXT),
CONTAINS(BOOLEAN),
WILDCARD(TEXT),
REGEXP(TEXT),
RANGE(TEXT)
private String searchType;
private SearchType(String type) {
searchType = type;
}
}
unfortunately it can't be done this way. Best solution I've come up with so far is to declare a nested interface to store constants...
public enum SearchType {
STARTS_WITH(Categories.TEXT),
ENDS_WITH(Categories.TEXT),
CONTAINS(Categories.BOOLEAN),
WILDCARD(Categories.TEXT),
REGEXP(Categories.TEXT),
RANGE(Categories.TEXT)
interface Categories{
static final String TEXT = "text";
static final String BOOLEAN = "boolean";
}
private String searchType;
private SearchType(String type) {
searchType = type;
}
}
so I'm wondering if there is a better way to do so?
I would use an enum for the Categories as well. If you place this in a top level class, it will look natural.
You have to define your enum values before any other constants.
AFAIK This is done to simplify the syntax. You have the enum values first with a special, simplified syntax, followed by the constants you define. The need for this is more obvious when you start overriding methods in your constants.
I created SomeConfig to store there static data. However I try to understand witch options is better (or none of both)
Before I had class SomeConfig written like:
public class SomeConfig {
private static int mValue = 8;
private static String mString = "some String";
public static int getValue() {
return mValue;
}
public static void setValue(int value) {
mValue = value;
}
public static String getTheString() {
return mString;
}
public static void setValue(String theString) {
mString = theString;
}
}
Now I changed it to:
public class SomeConfig {
private static SomeConfig mSomeConfig = new SomeConfig();
private int mValue = 8;
private String mString = "some String";
public static int getValue() {
return mSomeConfig.mValue;
}
public static void setValue(int value) {
mSomeConfig.mValue = value;
}
public static String getTheString() {
return mSomeConfig.mString;
}
public static void setValue(String theString) {
mSomeConfig.mString = theString;
}
}
Generally i changed private variables to non-static but API stays the same.
What is a difference between two options I posted?
Thanks,
If you want only one instance of your SomeConfig to exist in your application then you might want to make it a Singleton class. Refer to this link : link
Your second option seems to be the closest to being a Singleton, you just need to make your Default constructor Private to ensure that no other class can create another instance of SomeConfig.
As per my understanding static variables are class variable and those are not require any object for calling or assigning value .The values for those static variables are remains same over the class.Once you assign a value, all object can access that value.
Hope it will help you.
Generally, I think it's a good practice to avoid static variables and methods, unless there is a real need (I guess common use of static is "utility" type method, or constants etc). If you do not want to instantiate the class multiple times or want to ensure single instance of the configuration, I think implementing it as a singleton would be a better way to go here.
I wouldn't recommend using any of the two for configuration purposes.
The difference between these two are just that one uses an instance to hold the values, the other uses static variables.
You might look into having a configuration class that utilises a ResourceBundle to load the values from a .properties file during initialisation.
I have a lot of subclasses of an abstract class and each of them declare a public static final field with the same name. I was thinking of having this field in the abstract superclass without initializing it and hoping that each subclass would be forced to initialize it.
I was thinking of this because all of my subclasses of the abstract class declare a public static final String field called UNIQUE_ID, and it is necessary for every subclass to declare such a field with exactly that name.
I hope my question is clear enough, if not please tell me so.
Can something more or less equivalent to this be done?
EDIT: Code added:
My abstract class looks like:
public abstract class ExperimentPanelModel extends Panelizable {
protected String nextButtonText;
protected String backButtonText;
protected String skipButtonText;
protected Properties currentFile;
protected List<Properties> pastFiles = new ArrayList<Properties>();
public ExperimentPanelModel(Properties argcurrentfile, List<Properties> argpastfiles) {
currentFile = argcurrentfile;
pastFiles = argpastfiles;
nextButtonText = "Next";
backButtonText = "Back";
skipButtonText = "Skip";
}
...
}
Some of the non-abstract subclasses of that abstract class look like (note that all of them declare public static final String UNIQUE_ID) :
public class ConfigurationGUI extends ExperimentPanelModel {
public static final String UNIQUE_ID = "ConfigurationGUI";
public static final String DATA_MODIFIED = "DataModified";
Date dateOfLastSession;
int ExperimentalSession;
int ExperimentOrder;
boolean nextButtonEnabled = false;
public ConfigurationGUI(Properties argcurrentfile, List<Properties> argpastfiles) {
super(argcurrentfile, argpastfiles);
nextButtonText = "Confirm";
backButtonText = "Abort";
}
...
}
One example more:
public class Introduction extends ExperimentPanelModel {
public static final String UNIQUE_ID = "Introduction";
public static final String INSTRUCTIONS_XML_FILE = "instructions.xml";
public static final String THIS_INSTRUCTION_PROPERTY = UNIQUE_ID;
private String thisInstructionText = UNIQUE_ID;
Properties readInstructionsProperties = new Properties();
public Introduction(Properties argcurrentfile, List<Properties> argpastfiles) {
...
And the last one:
public class Instruction1 extends ExperimentPanelModel {
public static final String UNIQUE_ID = "Instruction1";
public static final String INSTRUCTIONS_XML_FILE = "instructions.xml";
public static final String THIS_INSTRUCTION_PROPERTY = UNIQUE_ID;
...
}
The field idea won't work, because static fields can't be overridden in subclasses. What you can do is you can declare an abstract method on the abstract class so that your subclasses must implement it.
Also note you can't make it a static method because those don't get overridden either.
In your case I would define the variable in the ancestor. No point in having a variable in each of the extending classes, unless you have a particularly good reason, which you don't sound like having.
+1 for Nathan's reply though. In quite a few cases, that's a better thing to do.
Put the public final field UNIQUE-ID in the abstract class and declare a protected constructor which takes the value for UNIQUE-ID. You'll not be able to make it static though as the values are required to be different for different instances.
Why can't enum's constructor access static fields and methods? This is perfectly valid with a class, but is not allowed with an enum.
What I'm trying to do is store my enum instances in a static Map. Consider this example code which allows lookup by abbreivation:
public enum Day {
Sunday("Sun"), Monday("Mon"), Tuesday("Tue"), Wednesday("Wed"), Thursday("Thu"), Friday("Fri"), Saturday("Sat");
private final String abbreviation;
private static final Map<String, Day> ABBREV_MAP = new HashMap<String, Day>();
private Day(String abbreviation) {
this.abbreviation = abbreviation;
ABBREV_MAP.put(abbreviation, this); // Not valid
}
public String getAbbreviation() {
return abbreviation;
}
public static Day getByAbbreviation(String abbreviation) {
return ABBREV_MAP.get(abbreviation);
}
}
This will not work as enum doesn't allow static references in its constructor. It however works just find if implemented as a class:
public static final Day SUNDAY = new Day("Sunday", "Sun");
private Day(String name, String abbreviation) {
this.name = name;
this.abbreviation = abbreviation;
ABBREV_MAP.put(abbreviation, this); // Valid
}
The constructor is called before the static fields have all been initialized, because the static fields (including those representing the enum values) are initialized in textual order, and the enum values always come before the other fields. Note that in your class example you haven't shown where ABBREV_MAP is initialized - if it's after SUNDAY, you'll get an exception when the class is initialized.
Yes, it's a bit of a pain and could probably have been designed better.
However, the usual answer in my experience is to have a static {} block at the end of all the static initializers, and do all static initialization there, using EnumSet.allOf to get at all the values.
Quote from JLS, section "Enum Body Declarations":
Without this rule, apparently reasonable code would fail at run time
due to the initialization circularity inherent in enum types. (A
circularity exists in any class with a "self-typed" static field.)
Here is an example of the sort of code that would fail:
enum Color {
RED, GREEN, BLUE;
static final Map<String,Color> colorMap = new HashMap<String,Color>();
Color() {
colorMap.put(toString(), this);
}
}
Static initialization of this enum type would throw a NullPointerException because the static variable colorMap is
uninitialized when the constructors for the enum constants run. The
restriction above ensures that such code won’t compile.
Note that the example can easily be refactored to work properly:
enum Color {
RED, GREEN, BLUE;
static final Map<String,Color> colorMap = new HashMap<String,Color>();
static {
for (Color c : Color.values())
colorMap.put(c.toString(), c);
}
}
The refactored version is clearly correct, as static initialization occurs top to bottom.
maybe this is what you want
public enum Day {
Sunday("Sun"),
Monday("Mon"),
Tuesday("Tue"),
Wednesday("Wed"),
Thursday("Thu"),
Friday("Fri"),
Saturday("Sat");
private static final Map<String, Day> ELEMENTS;
static {
Map<String, Day> elements = new HashMap<String, Day>();
for (Day value : values()) {
elements.put(value.element(), value);
}
ELEMENTS = Collections.unmodifiableMap(elements);
}
private final String abbr;
Day(String abbr) {
this.abbr = abbr;
}
public String element() {
return this.abbr;
}
public static Day elementOf(String abbr) {
return ELEMENTS.get(abbr);
}
}
The problem solved via a nested class. Pros: it's shorter and also better by CPU consumption. Cons: one more class in JVM memory.
enum Day {
private static final class Helper {
static Map<String,Day> ABBR_TO_ENUM = new HashMap<>();
}
Day(String abbr) {
this.abbr = abbr;
Helper.ABBR_TO_ENUM.put(abbr, this);
}
public static Day getByAbbreviation(String abbr) {
return Helper.ABBR_TO_ENUM.get(abbr);
}
When a class is loaded in the JVM then static fields are initialized in the order in which they appear in code. For e.g.
public class Test4 {
private static final Test4 test4 = new Test4();
private static int j = 6;
Test4() {
System.out.println(j);
}
private static void test() {
}
public static void main(String[] args) {
Test4.test();
}
}
The output will be 0. Note that test4 initialization takes place in static initialization process and during this time j is not yet initialized as it appears later. Now if we switch order of static initializers such that j comes before test4. The output will be 6.But in case of Enums we cannot alter order of static fields. The first thing in enum must be the constants which are actually static final instances of enum type.Thus for enums its always guaranteed that static fields wont be initialized before enum constants.Since we cannot give any sensible values to static fields for use in enum constructor, it would be meaningless to access them in enum constructor.