Tauriel
Tauriel

Reputation: 21

Null Pointer Exception in Java Enum

I'm learning Enum concept in java and I faced a problem while practicing.

Here is the code snippet,

public class MyClass {
    private String cardColor = CARDS.SPADE.cardColor; #Causes Null Pointer #Default Value
    private MyClass(CARDS card){
        this.cardColor = card.cardColor;
    }
    public static enum CARDS{
        SPADE("Black"),
        CLUB("Black"),
        DIAMOND("Red"),
        HEART("Red");
        private String cardColor = null;
        private MyClass obj = null;
        CARDS(String color){
            this.cardColor = color;
            obj = new MyClass(this);         #Trying to create object for MyClass 
        }
        public String getCardColor(){
            return this.cardColor;
        }
    }
    public static void main(String args[]) {
        System.out.println(CARDS.SPADE);
    }
}

I'm trying to create a MyClass object private to the enum in it's constructor. Here the value CARDS.SPADE is null and I end up with Null Pointer Exception.

If I don't create an object in enum constructor everything works perfect,

obj = new MyClass(this);

I'm not understanding why the static enum is not initialized and I'm confused with the control flow here. Can someone explain me what's wrong here?

Upvotes: 1

Views: 2847

Answers (1)

davidxxx
davidxxx

Reputation: 131336

You have a circular dependency : the initialization of the CARDS enum and the MyClass instance depend on each other.
CARDS constructor instantiates MyClass but MyClass constructor relies itself on the CARDS.SPADE state that is not still fully initialized as in the pending enum constructor.

Either break this cycle or do things in two times. Init the enum without the bidirectional relationship and after the constructor invocations, set the enum value to the MyClass instance via a setter.

Note that the "real" cause of the NullPointerException is that you don't refer to the currently instance created in the enum constructor (this) but you refer the enum value from the enum class itself : MyClass.CARD.SPADE.
The first has a state but the second not yet since the enum constructor has not returned yet.

By passing the enum instance into the constructor of MyClass it will "work" :

CARDS(String color){
        this.cardColor = color;
        obj = new MyClass(this);    
    }
}

// ...
public MyClass(CARDS cards){
     cardColor = cards.cardColor;
}

But in a general way, passing this during constructor body to another object/class not a good idea. This may leak to an inconsistent state if the object states changes between this time and the end of the constructor invocation.

Upvotes: 4

Related Questions