垃圾收集器运行在枚举types?

根据jls§8.9.2 Enum Body Declarations

枚举声明声明一个终结器是一个编译时错误。 一个枚举types的实例可能永远不会被最终确定。

当垃圾收集器运行之前执行终结器,如果终结器不存在,这意味着enumtypes总是保持加载在内存中,并且垃圾收集器不适用于enumtypes?

如果你编译一个枚举类似

 enum Suit {SPADES, HEARTS, CLUBS, DIAMONDS} 

您将看到生成的bytcodes(即javap -p Suit )对应于一个合成类:

 final class Suit extends java.lang.Enum<Suit> { public static final Suit SPADES; public static final Suit HEARTS; public static final Suit CLUBS; public static final Suit DIAMONDS; private static final Suit[] $VALUES; public static Suit[] values(); public static Suit valueOf(java.lang.String); private Suit(); } 

所以,枚举的实例是类本身的静态成员。 那么我认为这个垃圾收集的唯一方法就是如果这个类本身是垃圾收集的,如果这个类是由系统类加载器加载的话,这是不太可能发生的。

垃圾收集器运行在枚举types?

只是一个实验,以显示枚举实例可以使gc符合条件。

定义一个样本枚举如下 –

 public enum SampleEnum { ONE; } 

和testing代码 –

 Class<SampleEnum> clazz = SampleEnum.class; String[] fieldNames = { "ONE", "ENUM$VALUES" }; //create a weak reference to the instance WeakReference<SampleEnum> ref = new WeakReference<SampleEnum>(SampleEnum.ONE); //remove the hard references for (String fieldName: fieldNames) { Field feld = clazz.getDeclaredField(fieldName); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(feld, feld.getModifiers() & ~Modifier.FINAL); feld.setAccessible(true); feld.set(null, null); } //wait until a gc occurs and clears the weak ref while (ref.get() != null) { System.out.println("Waiting ..."); System.gc(); } //output just to verify that the weak ref is cleared by the gc System.out.println("Weak reference is cleared!"); 

尝试使用-verbose:gc选项。


当垃圾收集器运行之前执行终结器,如果终结器不存在,这意味着枚举types总是保持加载在内存中,并且垃圾收集器不适用于枚举types?

事实上,终结者的存在与否并不涉及任何对象是否被gc化。 枚举实例不被gc'ed,因为它们由编译器生成的enum类中的静态字段引用。

我相信因为枚举types和枚举types总是静态的,所以它会像静态成员一样,因为它可以在任何时候被访问。

此外,终结器被devise为在从内存中卸载对象时被调用,因为它们打算执行任何必要的清理操作,并且不能创buildEnum的对象。

这是一个好奇的几句话。

枚举声明声明一个终结器是一个编译时错误。

这很清楚。 我不知道为什么会这样,但规则是规则。 这也似乎是由枚举派生的事实强制执行,API规范说Enum有一个final终结者。

一个枚举types的实例可能永远不会被最终确定。

这里的语言对我来说似乎很模糊。 他们是否宣称没有任何枚举types的实例会被最终确定? 如果是这样,为什么“可能”呢? 为什么不直接说呢? 他们只是提醒我们,不能保证最终确定发生? 无论哪种方式,没关系….

Objectfinalize方法被定义为什么都不做( 12.6 )。 Enum派生自Object ,枚举派生自EnumEnum的终结器没有被定义为做任何事情,你不能覆盖它,所以当你把它放在一起时,枚举实例的终结没有影响。

在我的解释中,枚举实例可以被垃圾收集(虽然其他人已经指出,允许这种事情发生的情况有点不寻常),并且由于它们的finalize方法被定义为不做任何事情,不pipefinalize方法是曾经被称为是一个有争议的问题。