8

Please look at this link. In his book Effective Java, Joshua Bloch says

Note that the Operation constants are put into the stringToEnum map from a static block that runs after the constants have been created.

Trying to make each constant put itself into the map from its own constructor would cause a compilation error

. This is a good thing, because it would cause a NullPointerException if it were legal.

Enum constructors aren’t permitted to access the enum’s static fields, except for compile-time constant fields.

This restriction is necessary because these static fields have not yet been initialized when the constructors run.

I have two questions

  1. Can Enums have separate constructors for each constant?
  2. Why are compile time constant fields accessible in constructors but not static fields?

Thanks

Ankit
  • 251
  • 2
  • 9
  • Can you add code example for those who can't access it from your link? – Pshemo May 06 '15 at 07:24
  • @Pshemo, Yes Sir, This link contains whole Item 30 from Joshua Bloch's book Effective Java https://ly2xxx.wordpress.com/page/5/?app-download=ios – Ankit May 06 '15 at 07:29
  • I meant to put it directly in question. Links tend to break so when it happens your question will be useless for future readers. – Pshemo May 06 '15 at 07:35

3 Answers3

6

As for first question: you cannot have separate constructors, but you can work-around this in the following manner:

public enum EnumTest {
    ONE() {
        void init() {
            val = 2;
        }
    },
    TWO() {
        void init() {
            val = 1;
        }
    };

    protected int val;

    abstract void init();

    EnumTest() {
        init();
    }
}

This way you technically have separate initialization methods for different constants.

Another way is to use initializer sections:

public enum EnumTest {
    ONE() {{
            val = 2;
        }},
    TWO() {{
            val = 1;
        }};

    protected int val;
}

As for your second question: constant fields are not accessible during enum construction, because enum constants are accessible for static fields. For example, this code compiles correctly:

public enum EnumTest {
    ONE, TWO;

    public static final String ONE_STRING = ONE.toString();
}

If accessing ONE_STRING from the constructor were allowed, you would either had an endless initialization loop or accessing of not-yet-initialized enum constant.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
4
  1. No, and I don't think that is what Bloch means, although it has not been formulated in the best possible way. An enum can have constructors, as the enum Operation in the book has. What Bloch means with "its own constructor" is: when the constructor of Operation runs for that particular constant.

  2. This is already answered by what you quoted above:

    This restriction is necessary because these static fields have not yet been initialized when the constructors run.

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • So sorry I can accept only one answer. But I'll upvote your other answers to increase your numbers by +25 – Ankit May 07 '15 at 15:53
3

The regular rules for constructors apply. You can have as many constructors as you want so long as they have different signatures. Different enum values can then be built using different constructors:

enum StringAndNumber {
    Zero("zero"),
    Five(5),
    Pi("Pi", 3.14159);

    private final String str;
    private final Number num;

    private StringAndNumber(String str) {
        this.str = str;
        this.num = null;
    }

    private StringAndNumber(Number num) {
        this.num = num;
        this.str = null;
    }       

    private StringAndNumber(String str, Number num) {
        this.str = str;
        this.num = num;
    }
}
Misha
  • 27,433
  • 6
  • 62
  • 78
  • So sorry I can accept only one answer. But I'll upvote your other answers to increase your numbers by +25 – Ankit May 07 '15 at 15:52