自动导致释放子类JPanel的资源

时间:2011-05-31 15:03:17

标签: java swing resources

假设我是子类JPanel,而我的子类使用了大量内存。

我设计这个类的正确方法是什么,以便在我的JPanel用作更大系统中的组件时释放内存资源?

似乎有几个选择:

  1. 子类finalize()(遍布各地的红旗 - 我读过的文献说你不应该进入最终的业务)。
  2. 为我班级的消费者添加明确的dispose()destroy()或其他内容
  3. 向我的JPanel添加某种侦听器,当父级被处理时会收到通知
  4. 覆盖JPanel的一些方法,当它们的父窗口被处理时会自动被调用
  5. 在下面的示例中,我使用了finalize()选项,该选项仅在调用垃圾收集时才有效,并且有些情况下,当不再需要JPanel时,我宁愿进行清理。

    选项#2很不错,但是我必须依赖消费者来调用这个方法,并且Swing哲学似乎只是将组件粘贴到窗口中,并且当窗口关闭时让所有组件都被销毁。因此,如果我的JPanel位于JFrame中JPanel的JScrollPane中的JTable内部,那么我的班级的消费者可能不会调用我的dispose()destroy()方法。

    选项#3或#4将是我的选择,但我找不到任何似乎适用于此的内容。

    有什么建议吗?

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class JPanelMemoryHog extends JPanel
    {
        final private String title;
        final private Object space;
    
        public JPanelMemoryHog(String title)
        {
            super();
            this.title = title;
            this.space = new byte[5*1000*1000];
            setBorder(BorderFactory.createTitledBorder(title));
            setPreferredSize(new Dimension(300,200));
        }
    
        @Override protected void finalize()
        {
            System.out.println("finalized "+this.title);
        }
    
        public static void main(String[] args) {
            JFrame frame = new JFrame("example");
            JPanel panel = new JPanel();
            panel.setLayout(new BorderLayout());
            JButton button = new JButton("create frame");
            button.addActionListener(new ActionListener() {
                @Override public void actionPerformed(ActionEvent e) {
                    createFrame();
                }
            });
            panel.add(button, BorderLayout.CENTER);
            frame.setContentPane(panel);
            frame.pack();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    
        private static int panelcount = 0;
        protected static void createFrame() {
            final String title = "panel"+(++panelcount);
            final JFrame frame = new JFrame(title);
            frame.setContentPane(new JPanelMemoryHog(title));
            frame.pack();
            frame.addWindowListener(new WindowAdapter() {
                @Override public void windowClosing(WindowEvent e) {
                    System.out.println("closing "+title);
                    frame.dispose();
                }
            });
            frame.setVisible(true);
        }   
    }
    

2 个答案:

答案 0 :(得分:4)

最佳解决方案是向JPanel添加HierarchyListener,然后检查HierarchyEvent.DISPLAYABILITY_CHANGED(在显示和处理父对话框时触发),然后检查isDisplayable()到false,这是处理过程中设置的条件。

public void hierarchyChanged(HierarchyEvent e) {
   //check for Hierarchy event
   if(e.getChangeFlags() == HierarchyEvent.DISPLAYABILITY_CHANGED)
   {       
        //do the required action upon close
       if(!this.isDisplayable())                         
          Notifier.removeListener(this);

   }
}

答案 1 :(得分:0)

就像你提到的那样,不要调用finalize(),这只是危险而且很难做到。

我总是添加dispose方法来处理监听器清理和删除任何内存密集型资源。我认为正确地做到这一点的诀窍是,应该有一种处理器来破坏这些对象。

如果您正在谈论将在更通用的框架中使用的更通用的组件,这可能不是正确的解决方案