简体   繁体   English

为什么在枚举设置为null后保留此值

[英]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. 奇怪的是,在我将值明确设置为0之前,此内部值(在我的情况下为int)保持最高值。

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 我已经尝试过这些事情来将枚举值设置为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. 我认为您严重误解了Java枚举的目的和功能。 Enums are by definition singletons , meaning that every definition of an enum is constructed once and only once per runtime. 根据定义,枚举是singletons ,这意味着枚举的每个定义在每次运行时都只能构造一次。 In other words, you can't have two flags.None instances; 换句话说,您不能有两个flags.None flags.None is a single thing forever while your application is running. flags.None是一个单一的事情你永远的应用程序运行时。

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 . 就像您可能说int i = 0 ,您可以声明一个“ flags”变量,例如flags myFlag = flags.None This does not create a new version of "None", but it is a reference to the "None" enum. 这不会创建“ None”的新版本,而是对“ None”枚举的引用。 Modifying the state of "None" (which is a bad idea IMHO) will be seen globally throughout your application. 修改状态“ None”(恕我直言,这是个坏主意)将在整个应用程序中全局显示。

Also, you shouldn't roll your own bit-twiddling into the enums you write. 另外,您不应该将自己的琐事拖入编写的枚举中。 Might I suggest that you take a look at EnumSet ? 可能我建议您看看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). 问题是,枚举的每个值只有一个实例(在您的情况下为Noneflag1 )。 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. 如果将标志添加到None ,则原始的None实例将更改(与flags.None的相同),并且将一直保持这种状态,直到再次更改它为止。

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. 通过更改静态对象的成员(addFlag调用),您已经对其进行了修改,因此所有其他引用都将引用该相同的值。

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. 您误解的另一部分是,当您将标志分配给null或另一个值时,您并没有清除枚举。 Java is pass by reference and so all you are doing is changing what the flag variable is referring to. Java是按引用传递的,因此您要做的就是更改flag变量所引用的内容。 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. 这就是为什么在代码末尾,当您将Value设置为0时,枚举的None成员再次按预期显示0。 You can play around with this by reassigning both the None and the flag1 enum members' values. 您可以通过重新分配None和flag1枚举成员的值来解决这个问题。

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. 当然,您显然可以做到这一点,我只是说这可能会使看到您工作的其他人感到困惑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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