Хорошо, давайте попробуем это. Это небольшое Java-приложение для динамического создания JButton. Я пытаюсь найти способ полностью удалить созданные JButtons, чтобы сборщик мусора освободил память, которую они использовали. ЭТО МИНИМАЛЬНЫЙ ВОСПРОИЗВОДИМЫЙ ПРИМЕР, иллюстрирующий то, чего я пытаюсь достичь.
Таким образом, пользователь может установить положение элемента управления по x и y и нажать кнопку «Создать», и JButton станет называться myButton. Теперь мне бы хотелось, чтобы кнопка «Удалить» удаляла, делала нулевыми все созданные кнопки. Я знаю, что могу сделать его невидимым, удалить из контейнера и т. д., но я хочу его уничтожить.
Вопрос 1: Насколько я понимаю, если я установлю объект = null, он позволит собрать мусор и удалить его из памяти? Итак, если я сделаю myButton=null, можно ли будет удалить этот объект из памяти?
Вопрос 2: Если вопрос 1 верен, я знаю, что при создании все кнопки нового объекта будут иметь одно и то же имя. Итак, как мне динамически создавать их экземпляры, сохраняя при этом возможность уничтожить их позже? Я пробовал использовать ListArray, и хотя у меня есть к ним доступ, я не могу обнулить их.
Вопрос 3. Когда в контейнер добавляется еще одна кнопка, этот объект по-прежнему работает правильно, даже если я создаю еще одну кнопку J, которая заменяет содержимое исходной кнопки myButton. Наверное, меня смущает процесс, который происходит между созданием экземпляра и добавлением его в контейнер.
То, что я пытаюсь сделать, просто невозможно, это грубая концептуальная ошибка с моей стороны, или есть способ сделать это?
package makeControls;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
public class MakeControls {
private JFrame frame;
private JTextField txtXPosition;
private JTextField txtYPosition;
private JButton btnDelete;
private JButton myButton;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MakeControls window = new MakeControls();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MakeControls() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton btCreateButton = new JButton("Create Button");
btCreateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myButton = new JButton(); // create new button
int x = Integer.valueOf(txtXPosition.getText());
int y = Integer.valueOf(txtYPosition.getText());
myButton.setBounds( x,y,50,20); // set bounds based on entered values
frame.getContentPane().add(myButton);
myButton.setVisible(true);
frame.repaint();
}
});
btCreateButton.setBounds(222, 11, 146, 23);
frame.getContentPane().add(btCreateButton);
txtXPosition = new JTextField();
txtXPosition.setText("X Position");
txtXPosition.setHorizontalAlignment(SwingConstants.LEFT);
txtXPosition.setBounds(36, 12, 86, 20);
frame.getContentPane().add(txtXPosition);
txtXPosition.setColumns(10);
txtYPosition = new JTextField();
txtYPosition.setText("Y Position");
txtYPosition.setBounds(126, 12, 86, 20);
frame.getContentPane().add(txtYPosition);
txtYPosition.setColumns(10);
btnDelete = new JButton("Delete All");
btnDelete.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Deleting");
myButton = null;
}
});
btnDelete.setBounds(222, 50, 146, 23);
frame.getContentPane().add(btnDelete);
}
}
Как обычно, заранее благодарю.
Этот блок кода не создает и не предотвращает утечку памяти. Если у вас есть утечка памяти, возьмите дамп кучи и проанализируйте его с помощью Eclipse MAT — это даст вам лучшие подсказки о том, где происходит утечка памяти, чем публикация некоторых фрагментов кода в stackoverflow.
Почему ты поставил c = null; в блок try?
Сообщение заменено на MRE. Это помогло мне продумать эту проблему, пока я ее писал, но до сих пор не могу найти способ выполнить свою задачу, если это возможно. Пожалуйста, смотрите пост.




Я изменил ваш код, чтобы создать следующий графический интерфейс.
Я разделил JFrame на два JPanels. JPanel слева — это место, где появятся элементы управления, созданные пользователем. JPanel справа содержит элементы управления графическим интерфейсом.
Причина, по которой я это сделал, заключалась в том, чтобы не дать пользователю накладывать элементы управления графического интерфейса и отделить элементы управления графического интерфейса от элементов управления, созданных пользователем. Это станет важным, когда мы удалим созданные пользователем элементы управления.
Вот графический интерфейс с созданным пользователем JButton. Я поместил текст на JButtons, чтобы можно было отличить их друг от друга.
У Oracle есть полезное руководство Создание графического интерфейса с помощью Swing. Пропустите раздел «Обучение с использованием среды IDE NetBeans». Добавьте в закладки и изучите оставшуюся часть урока.
Я использовал JFrame по умолчанию BorderLayout. Я создал элементы управления графического интерфейса JPanel, используя GridLayout внутри FlowLayout. GridLayout делает четыре компонента Swing равными по размеру и размещает их в два ряда по два столбца. FlowLayout делает GridLayoutJPanel минимальным размером.
Созданные пользователем элементы управления JPanel имеют макет null и начальный размер. Вы можете сделать JPanel больше или меньше, изменив размер JFrame. Один из способов — максимизировать JFrame.
Чтобы удалить все созданные пользователем элементы управления, я удаляю компоненты Swing из созданных пользователем элементов управления JPanel. Мне не нужно беспокоиться об удалении компонентов Swing с графическим интерфейсом.
Вот полный работоспособный код.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MakeControls {
private int buttonCounter;
private JFrame frame;
private JPanel makeControlsPanel;
private JTextField txtXPosition;
private JTextField txtYPosition;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
new MakeControls();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MakeControls() {
this.buttonCounter = 1;
this.makeControlsPanel = createMakeControlsPanel();
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame("Make Controls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(makeControlsPanel, BorderLayout.CENTER);
frame.add(createControlPanel(), BorderLayout.EAST);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMakeControlsPanel() {
JPanel panel = new JPanel(null);
panel.setPreferredSize(new Dimension(500, 500));
return panel;
}
private JPanel createControlPanel() {
JPanel outerPanel = new JPanel(new FlowLayout());
JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton btCreateButton = new JButton("Create Button");
btCreateButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
JButton button = new JButton("Button " + buttonCounter++);
int x = Integer.valueOf(txtXPosition.getText());
int y = Integer.valueOf(txtYPosition.getText());
Dimension d = button.getPreferredSize();
button.setBounds(x, y, d.width + 10, d.height);
makeControlsPanel.add(button);
frame.repaint();
}
});
panel.add(btCreateButton);
JButton btnDelete = new JButton("Delete All");
btnDelete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
int size = makeControlsPanel.getComponentCount();
for (int index = size - 1; index >= 0; index--) {
makeControlsPanel.remove(index);
}
buttonCounter = 1;
frame.repaint();
}
});
panel.add(btnDelete);
txtXPosition = new JTextField(10);
txtXPosition.setText("X Position");
panel.add(txtXPosition);
txtYPosition = new JTextField(10);
txtYPosition.setText("Y Position");
panel.add(txtYPosition);
outerPanel.add(panel);
return outerPanel;
}
}
Я не ответил на вопросы.
Вопрос 1: Насколько я понимаю, если я установлю объект = null, он позволит собрать мусор и удалить его из памяти? Итак, если я сделаю myButton=null, можно ли будет удалить этот объект из памяти?
Да, но вам не обязательно этого делать. Когда вы удаляете компонент Swing из JPanel, процесс удаления позволит выполнить сборку мусора для компонента Swing.
Вопрос 2: Если вопрос 1 верен, я знаю, что при создании все кнопки нового объекта будут иметь одно и то же имя. Итак, как мне динамически создавать их экземпляры, сохраняя при этом возможность уничтожить их позже? Я пробовал использовать ListArray, и хотя у меня есть к ним доступ, я не могу обнулить их.
Вы удаляете компоненты Swing, получая компоненты из JPanel и удаляя их.
Вопрос 3. Когда в контейнер добавляется еще одна кнопка, этот объект по-прежнему работает правильно, даже если я создаю еще одну кнопку J, которая заменяет содержимое исходной кнопки myButton. Наверное, меня смущает процесс, который происходит между созданием экземпляра и добавлением его в контейнер.
JPanel сохраняет ссылки на созданные пользователем JButtons. Код вашего приложения не обязательно должен хранить ссылки.
Вы противоречите сами себе. В конце вы правильно говорите: «JPanel поддерживает ссылки на созданные пользователем JButtons», поэтому не следует отвечать «да» на вопрос 1, так как установка переменной в ноль не позволит выполнить сборку мусора кнопок.
@Holger: Объект myButton, на который ссылается OP, выйдет за пределы области действия в конце метода btCreateButtonactionPerformed. Ничего не изменится, если он добавит myButton=null; в конец метода. Эта строка необязательна, но она не является недействительной.
Вопрос был не в том, действительна или недействительна строка, а в том, сделает ли она кнопку сборщиком мусора. И ответ — нет, поскольку, как вы правильно сказали в вопросе 3, панель по-прежнему содержит ссылки на кнопку (кнопки), присвоение переменной значения null не делает кнопку (кнопки) пригодными для сбора мусора. Кроме того, переменная myButton не выходит за пределы области видимости в конце метода, поскольку это не локальная переменная, а поле экземпляра внешнего объекта.
Писать
c = null;— нонсенс.c— это локальная переменная, которая выходит за пределы области видимости после завершения цикла (при повторении цикла она будет ссылаться на другой объект). Окружать это утверждение блокомtry/catchтакже бессмысленно:c = null;не может генерировать исключение.