简体   繁体   中英

Why is does this value get retained after enum is set to null

When trying to create a flag enum to let it contain multiple states. I've noticed something odd. When changing the inner value of the enum the name of it doesn't change. The odd part is that this inner value (in my case an int) stays the highest value until I explicitly set the value to 0.

This is the enum I've used to further test this

public enum flags {
   None(0), flag1(1 << 0);

   private int value;

   private flags(int value) {
       this.value = value;
   }

   public boolean hasFlag(flags flag) {
       return (flag.value & value) == flag.value;
   }

   public void addFlag(flags flag) {
       value |= flag.value;
   }

   public int getValue() {
       return value;
   }

   public void setValue(int value) {
      this.value = value;
   }
}

I have tried these things to set the enum value to 0

    flags flag = flags.None;
    System.out.println(flag + " " + flag.getValue());
    // prints: None 0

    flag.addFlag(flags.flag1);
    System.out.println(flag + " " + flag.getValue());
    // prints: None 1

    flag = flags.None;
    System.out.println(flag + " " + flag.getValue());
    // prints: None 1 even though
    // its been set to flags.None which has a value of 0

    flag = null;
    flag = flags.None;
    System.out.println(flag + " " + flag.getValue());
    // prints: None 1. Even though the enum has been set to null before
    // setting the value to null

    flag = null;
    flag = flags.flag1;
    flag = flags.None;
    System.out.println(flag + " " + flag.getValue());
    // prints: None 1. Even though it is set to
    // another value after being set to null
    // and then set to None

    flag.setValue(0);
    System.out.println(flag + " " + flag.getValue());
    // prints: None 0. As expected

My question is as follows: Why is the value so persistent, what's happening here?

I think that you are critically misunderstanding the purpose and functionality of Java's enums. Enums are by definition singletons , meaning that every definition of an enum is constructed once and only once per runtime. In other words, you can't have two flags.None instances; flags.None is a single thing forever while your application is running.

You can --however--declare multiple fields that reference your enumerations. Just like you might say int i = 0 , you can declare a "flags" variable like flags myFlag = flags.None . This does not create a new version of "None", but it is a reference to the "None" enum. Modifying the state of "None" (which is a bad idea IMHO) will be seen globally throughout your application.

Also, you shouldn't roll your own bit-twiddling into the enums you write. Might I suggest that you take a look at EnumSet ? This will produce much more readable code, and is the favorable way to implement what it looks like you're trying to accomplish.

The problem is, that enums only have one instance for each value ( None and flag1 in your case). Hence editing this one instance, will change it forever. If you add a flag to None , the original None instance is change (which is the same as in flags.None ), and will remain that way until you change it again.

When you declare an enum you are effectively declaring a series of static objects. By changing the member of the static object (the addFlag call) you have modified it and so all further references will reference that same value.

Another part of what you are misunderstanding is that when you assign flag to null or another value you are not wiping out the enum. Java is pass by reference and so all you are doing is changing what the flag variable is referring to. That is why at the end of your code, when you setValue to 0 the None member of the enum once again displays 0 as expected. You can play around with this by reassigning both the None and the flag1 enum members' values.

Lastly, this is really not how an enum is meant to be used. I'm not sure what you're attempting to use this for but you could just as easily be using a regular class based on what you have provided here. An enum is better used when you want strict type checking and clear indication (naming of) what each value means; eg an error code enum. But the values within should not be reassigned or modified. Of course obviously you can do this, I'm just saying it may confuse others that see your work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM