由于终结器在垃圾收集器运行之前执行,如果没有终结器,这是否意味着
enum
类型始终保留在内存中,并且垃圾回收器无法应用于enum
类型?enum
类型始终保留在内存中,并且垃圾回收器无法应用于enum
类型?如果您编译类似于枚举的东西
enum Suit {SPADES, HEARTS, CLUBS, DIAMONDS}
您将看到生成的字节码(即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();
}
因此,枚举的实例是类本身的静态成员。我认为唯一可能导致垃圾回收的方式是如果类本身被垃圾回收,但如果它是由系统类加载器加载的话,这种情况是非常不可能发生的。
垃圾回收器会运行在枚举类型上吗?
只是一个实验,以展示枚举实例可以被标记为垃圾回收对象。
定义一个样本枚举如下 -
public enum SampleEnum { ONE; }
测试代码如下 -
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
选项。
由于finalizer在垃圾回收运行之前执行,如果没有finalizer是否意味着枚举类型始终保留在内存中,并且垃圾回收器不适用于枚举类型?
实际上,有无finalizer与任何对象是否被垃圾回收没有任何关系。枚举实例不会被垃圾回收,因为它们由编译器生成的枚举类中的静态字段引用。
我认为,由于枚举(enum)和枚举类型(enum types)始终是静态(static)的,因此它的行为就像一个静态成员一样,因为可以在任何时间访问它。
此外,finalizers被设计为在对象从内存中卸载时调用,因为它们旨在执行任何必要的清理操作,并且您无法创建枚举(enum)的对象。
这是一对奇怪的句子。
声明枚举类型不得声明finalizer是编译时错误。
这已经很清楚了。我不知道为什么会这样,但规则就是规则。这似乎也得到了证实,因为枚举派生自Enum
,而API规范表明Enum
具有一个final
finalizer。
枚举类型的实例可能永远不会被终结。
这里的语言对我来说似乎有歧义。他们是否宣称枚举类型的任何实例都不会被终结?如果是这样,为什么用“可能”?为什么不直接说?他们只是提醒我们最终化不能保证发生吗?无论如何,都无关紧要...
Object
的finalize
方法被定义为空(12.6)。Enum
派生自Object
,而枚举派生自Enum
。Enum
的finalizer未被定义做任何事情,并且您无法重写它,因此将所有内容组合起来,枚举实例的最终化没有任何效果。
在我的解释中,枚举实例可以进行垃圾回收(尽管正如其他人指出的那样,允许这种情况发生的情况有点不寻常),并且由于它们的finalize
方法被定义为空,无论是否调用finalize
方法都没有意义。