gpt4 book ai didi

java - 即将被收集时如何获取java对象本身

转载 作者:行者123 更新时间:2023-11-30 02:13:44 25 4
gpt4 key购买 nike

如果我们无法控制对象的源(无法强制实现某些接口(interface)或最终 block ),那么在对象被收集之前,我们如何使用该对象执行一段代码(需要其状态)?

Java引用类型允许我们访问一个对象,如果其他人使它强可达+如果我们使用引用队列,我们​​也可以在对象被收集时收到通知,除非我的理解是错误的,这就是你可以用引用类型做的所有事情,无论你在任何时候使用什么,对象要么是强可达的,要么是消失了并且你有空。

我真正需要的是一种在即将收集特定对象时收到通知的方法。

最佳答案

Reference API 不允许检索收集的对象是有原因的:允许再次访问收集的对象,就像使用 finalize() 方法一样,正是这样并非有意为之。

标准方法是创建引用类型的子类来存储与所指对象关联的信息,例如在专门的引用对象中执行清理操作所需的一切。当然,此信息不得包含对所指对象本身的强引用。

private static final ReferenceQueue<Integer> QUEUE = new ReferenceQueue<>();
static class IntegerPhantomReference extends PhantomReference<Integer> {
final int value;
public IntegerPhantomReference(Integer ref) {
super(ref, QUEUE);
value = ref.intValue();
}
public String toString() {
return "Integer[value="+value+"]";
}
}
private static final Set<IntegerPhantomReference> REGISTERED = new HashSet<>();
public static void main(String[] args) throws InterruptedException {
List<Integer> stronglyReferenced = new ArrayList<>();
for(int i = 0; i < 10; i++) {
Integer object = new Integer(i);
stronglyReferenced.add(object);
REGISTERED.add(new IntegerPhantomReference(object));
}
gcAndPoll("initial");
stronglyReferenced.removeIf(i -> i%2 == 0);
gcAndPoll("after removing even");
stronglyReferenced.clear();
gcAndPoll("after remove all");
if(REGISTERED.isEmpty()) System.out.println("all objects collected");
}
private static void gcAndPoll(String msg) throws InterruptedException {
System.out.println(msg);
System.gc(); Thread.sleep(100);
for(;;) {
Reference<?> r = QUEUE.poll();
if(r == null) break;
System.out.println("collected "+r);
REGISTERED.remove(r);
}
}
initial
after removing even
collected Integer[value=4]
collected Integer[value=8]
collected Integer[value=6]
collected Integer[value=2]
collected Integer[value=0]
after remove all
collected Integer[value=1]
collected Integer[value=5]
collected Integer[value=3]
collected Integer[value=7]
collected Integer[value=9]
all objects collected
<小时/>

为了完整起见,有一个 hack 允许复活收集的对象,这将在 Java 9 中停止工作。

PhantomReference 的文档说:

Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued.

目前尚不清楚为什么要指定此值以及 get() method of PhantomReference已被重写为始终返回 null,这正是为了禁止从该引用尚未清除的事实中获得任何好处。由于这种特殊行为的目的尚不清楚,因此它已从 Java 9 的规范中删除,并且这些引用会像其他引用一样自动清除。

但对于以前的版本,可以使用带有访问覆盖的反射来访问指示对象,以准确执行 API 不允许的操作。不用说,这只是为了提供信息,强烈建议不要这样做(正如前面所说,它在 Java 9 中停止工作)。

private static final ReferenceQueue<Integer> QUEUE = new ReferenceQueue<>();
private static final Set<PhantomReference<Integer>> REGISTERED = new HashSet<>();
public static void main(String[] args)
throws InterruptedException, IllegalAccessException {
List<Integer> stronglyReferenced = new ArrayList<>();
for(int i = 0; i < 10; i++) {
Integer object = new Integer(i);
stronglyReferenced.add(object);
REGISTERED.add(new PhantomReference<>(object, QUEUE));
}
gcAndPoll("initial");
stronglyReferenced.removeIf(i -> i%2 == 0);
gcAndPoll("after removing even");
stronglyReferenced.clear();
gcAndPoll("after remove all");
if(REGISTERED.isEmpty()) System.out.println("all objects collected");
}
static final Field REFERENT;
static {
try {
REFERENT = Reference.class.getDeclaredField("referent");
REFERENT.setAccessible(true);
} catch (NoSuchFieldException ex) {
throw new ExceptionInInitializerError(ex);
}
}
private static void gcAndPoll(String msg)
throws InterruptedException, IllegalAccessException {
System.out.println(msg);
System.gc();
Thread.sleep(100);
for(;;) {
Reference<?> r = QUEUE.poll();
if(r == null) break;
Object o = REFERENT.get(r);
System.out.println("collected (and now resurrected)"+o);
REGISTERED.remove(r);
}
}

关于java - 即将被收集时如何获取java对象本身,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49290487/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com