有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java有没有一种安全的方法可以使用Cleaner注销侦听器?

我有一个摇摆动作类,其工作原理如下:

package org.trypticon.hex.gui.datatransfer;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorListener;
import java.awt.event.ActionEvent;
import javax.annotation.Nonnull;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.TransferHandler;

import org.trypticon.hex.gui.Resources;
import org.trypticon.hex.gui.util.FinalizeGuardian;
import org.trypticon.hex.gui.util.FocusedComponentAction;

public class PasteAction extends FocusedComponentAction {
    private final FlavorListener listener = (event) -> {
        // this method in the superclass calls back `shouldBeEnabled`
        updateEnabled();
    };

    @SuppressWarnings({"UnusedDeclaration"})
    private final Object finalizeGuardian = new FinalizeGuardian(() -> {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.removeFlavorListener(listener);
    });

    public PasteAction() {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.addFlavorListener(listener);
    }

    @Override
    protected boolean shouldBeEnabled(@Nonnull JComponent focusOwner) {
        TransferHandler transferHandler = focusOwner.getTransferHandler();
        if (transferHandler == null) {
            return false;
        }

        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        DataFlavor[] flavorsInClipboard = clipboard.getAvailableDataFlavors();
        return transferHandler.canImport(focusOwner, flavorsInClipboard);
    }

    @Override
    protected void doAction(@Nonnull JComponent focusOwner) throws Exception {
        Action action = TransferHandler.getPasteAction();
        action.actionPerformed(new ActionEvent(
            focusOwner, ActionEvent.ACTION_PERFORMED, (String) action.getValue(Action.NAME)));
    }
}

这里提到的FinalizeGuardian目前使用finalize()实现:

package org.trypticon.hex.gui.util;

public final class FinalizeGuardian {
    private final Runnable cleanupLogic;

    public FinalizeGuardian(Runnable cleanupLogic) {
        this.cleanupLogic = cleanupLogic;
    }

    @Override
    protected final void finalize() throws Throwable {
        try {
            cleanupLogic.run();
        } finally {
            super.finalize();
        }
    }
}

因此,出于显而易见的原因,我想切换到使用Cleaner来实现这一点

第一次尝试是这样的:

package org.trypticon.hex.gui.util;

import java.lang.ref.Cleaner;

public final class FinalizeGuardian {
    private static final Cleaner cleaner = Cleaner.create();

    public FinalizeGuardian(Runnable cleanupLogic) {
        cleaner.register(this, cleanupLogic);
    }
}

问题是,现在对象永远无法到达幻影,因为:

  • Cleaner本身对cleanupLogic
  • cleanupLogic保存对listener的引用,以便删除侦听器
  • listener持有对action类的引用,以便对其调用updateEnabled
  • action类持有对FinalizeGuardian的引用,这样就不会过早地收集它

因为FinalizeGuardian本身永远无法访问幻影,所以永远不会调用清理器

所以我想知道的是,有没有一种方法来重组它,以遵循规则,使Cleaner正确工作,不涉及通过将侦听器移动到我的action类之外来破坏封装


共 (0) 个答案