Java枚举实例的生命周期

Life span of a Java enum instance

我了解枚举类型的每个预定义常量只有一个实例。对吗?现在,假设枚举中有一个名为value的实例变量,并且假设ONE是一个预定义的常量。如果修改value作为ONE的实例,那么这将影响引用ONE的所有变量。但是当垃圾收集器除去枚举的所有实例时,EDOCX1的值会发生什么变化?他们有没有被抛弃过?

例子

这里有一个简单的例子,其中有两个变量AB,都指ONE。在首次使用B之前,value的值为负数。如果垃圾收集器在行Number B = Number.ONE;之前除去了ONE的实例,那么value的值就会"重置"回1,我想。这是正确的吗?

枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
public enum Number
{
    ONE(1), TWO(2), THREE(3);

    int value;

    Number(int value) { this.value = value; }

    void negate() { value = -value; }

    @Override
    public String toString() { return"value:" + value; }
}

主要方法:

1
2
3
4
5
6
7
8
public static void main(String[] args)
{
    Number A = Number.ONE;
    A.negate();
    Number B = Number.ONE;

    System.out.println(A +"  " + B);
}

输出:

value: -1 value: -1

所以我的问题是,输出是否可以是以下内容(如果在使用B之前添加A = null;)?

value: -1 value: 1


枚举是隐式的public static final字段,因此它们不会被垃圾收集。

编辑

正如@realc怀疑论者在评论中指出的那样,在一个具有多个类加载器的JVM实例中,情况稍微复杂一些。然后,静态字段值在卸载类时可能会消失。

但是,默认情况下,只要JVM实例是活动的,就只有一个类加载器是活动的,因此在您的示例应用程序中,静态字段永远不会被垃圾收集。


对于这个枚举:

1
2
3
public enum FooEnum {
  CONST
}

生成此字节代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Compiled from"FooEnum.java"
public final class FooEnum extends java.lang.Enum<FooEnum> {
  public static final FooEnum CONST;

  static {};
    Code:
       0: new           #1                  // class FooEnum
       3: dup
       4: ldc           #12                 // String CONST
       6: iconst_0
       7: invokespecial #13                 // Method"<init>":(Ljava/lang/String;I)V
      10: putstatic     #17                 // Field CONST:LFooEnum;
      13: iconst_1
      14: anewarray     #1                  // class FooEnum
      17: dup
      18: iconst_0
      19: getstatic     #17                 // Field CONST:LFooEnum;
      22: aastore
      23: putstatic     #19                 // Field ENUM$VALUES:[LFooEnum;
      26: return

  public static FooEnum[] values();
    // elided

  public static FooEnum valueOf(java.lang.String);
    // elided
}

const是最后一个静态变量,它的生存期是类的。

只有当类被垃圾收集时,枚举才会被垃圾收集。

从Java语言规范,Java SE 8版第8.9节。枚举类型:

An enum type has no instances other than those defined by its enum constants. It is a compile-time error to attempt to explicitly
instantiate an enum type (§15.9.1).

In addition to the compile-time error, three further mechanisms ensure
that no instances of an enum type exist beyond those defined by its
enum constants:

The final clone method in Enum ensures that enum constants can never
be cloned.

Reflective instantiation of enum types is prohibited.

Special treatment by the serialization mechanism ensures that
duplicate instances are never created as a result of deserialization.