JPanel с анонимным EventListener - почему GC не уничтожает слушателя?
Я просматривал открытый исходный код JMapViewer. Если кто-то еще хочет посмотреть на это, проверьте SVN.
Короче говоря, основной класс JMapViewer
, который является продолжением JPanel
, Есть еще один очень важный класс под названием DefaultMapController
который действует как MouseListener
для основного класса.
Первая странная вещь, которую я заметил, это то, что у зрителя нет ссылок на контроллер. JMapViewer
конструктор создает анонимный экземпляр DefaultMapController
, как это:
public JMapViewer() {
// other stuff
new DefaultMapController(this);
}
Мне кажется, что это плохой выбор дизайна, поскольку в контроллере есть множество методов (опций, переключателей и т. Д. - пример, показанный ниже), к которым теперь вообще нельзя получить доступ, так что же они хороши?
public void setMovementMouseButton(int movementMouseButton) {
// changes which mouse button is used to move the map
}
Контроллер имеет ссылку на зрителя, как показано в первом фрагменте выше, как он может осуществлять управление.
Однако потом я подумал о чем-то еще более странном! Если этот анонимный экземпляр слушателя не имеет ссылок, почему он может даже выжить? Разве GC не должен уничтожить это быстро? Или GC достаточно умен, чтобы знать, что класс слушателя ссылается на живой JComponent
также должны остаться в живых, чтобы работать должным образом, даже если у него нет названия по какой-то странной причине?
Итак, два реальных вопроса:
- почему GC не разрушает объект?
- действительно ли это плохой выбор дизайна или есть какой-то способ, которым я не знаю, чтобы получить доступ к контроллеру из класса, который создает экземпляр зрителя?
Я хочу внести свой вклад в эту библиотеку с открытым исходным кодом, и моя первая идея для изменения состоит в том, чтобы изменить JMapViewer
класс, чтобы иметь поле, ссылающееся на его контроллер, и изменить конструктор, чтобы назначить текущий анонимный контроллер этому новому полю. Но я хочу убедиться, что я ничего не упускаю по невежеству. Я искал всю кодовую базу для текста DefaultMapController
и это происходит только в его собственных определениях классов и в анонимных экземплярах в JMapViewer
Конструкторы.
РЕДАКТИРОВАТЬ:
Действительно, кажется, что есть способ получить доступ к анонимным слушателям, используя java.awt.Component
метод getMouseListeners()
, Так что технически в моем приложении я мог искать в этой коллекции экземпляры DefaultMapController
и используйте это для доступа к методам, которые мне нужны для изменения параметров контроллера.
Чтобы сыграть в адвоката дьявола, если я пойду с оригинальной идеей и дам карте ссылку на свой контроллер, то теперь у меня есть своего рода круговая ссылка (карта знает о контроллере, а контроллер знает о карте). Это плохая идея?
2 ответа
Абстрактный родитель, JMapController
, содержит ссылку на JMapViewer
прошел там мимо DefaultMapController
конструктор:
public DefaultMapController(JMapViewer map) {
super(map);
}
Приложение: The map
ссылка, удерживаемая контроллером, используется (выборочно) для добавления до трех ссылок контроллера на карту EventListenerList
обсуждается здесь. Любой из них исключает GC. По крайней мере одно полезное преимущество дизайна заключается в том, что бетон JMapController
нужно только реализовать доступные интерфейсы.
Как предлагается в этом наброске MVC, было бы необычно давать представлению ссылку на контроллер. Напротив, нет ничего плохого в том, чтобы позволить контроллеру зарегистрироваться в качестве слушателя представления, как предлагается здесь.
Обратите внимание, что только без аргументов JMapViewer
конструктор устанавливает DefaultMapController
, Вы можете использовать альтернативный конструктор, как отмечено в комментариях в строке 57-59 в редакции 29113 Demo.java
, Полный пример рассматривается здесь.
1) Все, что вы знаете, это то, что, если и когда виртуальная машина сочтет это целесообразным, она будет собирать некоторые или все мертвые объекты. GC не обязан ничего делать.
2) Лучше всего обратиться к хранителю библиотеки. В любом случае, как правило, я бы не стал ничего менять, если нет веской причины, например, если это заметно улучшает читабельность и скорее сосредоточится на реальных проблемах.
3) Не уверен, что это так, но когда вы сериализуете JComponent, вы также сериализуете все его поля. И вы не хотите сериализовать много неиспользованных вещей.