问题
I'll try to explain my problem as clear as possible :). I am using PropertyChangeSupport to notify registered views for changes in the properties. One of the property is an object which properties are changed every view seconds. I don't want to create for this particular object new instance every time it is being updated (for the propertychangelistener to notice the change), so I wrote my own equals method where I ommit the comparation to itself.
@Override
public boolean equals(Object item) {
// do not compare
// if (this == item) { return true; }
if (!(item instanceof TransferQueueItem) ||
item == null) {
return false;
}
TransferQueueItem newItem = (TransferQueueItem) item;
boolean value =
// ommited... properties comparation
return value;
}
Unfortunatelly that doesn't have the effect I was looking for. If I create a copy of the object and fire the property change method on it, then it works fine.
What am I missing here?
-- Edit
I realized, that since I am using the same instance and not a copy of it, the properties are pointig the same place, thus the comparation would always come out true. Is there a workaround to that (besides creating a copy). Or how bad is to create a copy of an object every second, eg.
回答1:
You must always return true
to tell PropertyChangeSupport
that your object did not change. But that means equals()
is broken for all objects of this class (so you can't use them in sets or maps anymore, for example).
A better way would be to have a special method firePropertyChange()
for this kind of object which does the special handling. This way, you can even avoid to create an instance of PropertyChangeEvent
, too. Here is an example for handling BigDecimal
(where equals()
doesn't work at all):
protected transient PropertyChangeSupport changeSupport = null;
public void addPropertyChangeListener (String propertyName, PropertyChangeListener listener)
{
if (changeSupport == null)
changeSupport = new PropertyChangeSupport (this);
changeSupport.addPropertyChangeListener (propertyName, listener);
}
public void firePropertyChange (String propertyName, BigDecimal oldValue, BigDecimal newValue)
{
if (changeSupport == null)
return;
if (oldValue != null && newValue != null && oldValue.compareTo (newValue) == 0) {
return;
}
changeSupport.firePropertyChange(new PropertyChangeEvent(this, propertyName,
oldValue, newValue));
}
[EDIT] What you do is something else entirely: You have a parent and a child and you want listeners of the parent to receive events when the child changes.
The correct approach here is to add PropertyChangeSupport
to the child. When the child is added to the parent, the parent must install the necessary listeners in the child. When an event is fired, it must fire a second event which informs the listeners of the parent of the change in the child (the parent must forward the events).
回答2:
this is a case of chained propertychangelisteners:
TransferQueueItem should launch their own PropertychangeEvents which must be listened by the TransferQueue in which is inserted
And in response TransferQueue must notify their listeners that an owned item has changed.
Every time i have a problem like this in which an object must relaunch events i use this convention (of my work team):
1 An object can only launch events which source is itself.
2 If it want delegate event it launchs an event like this: new PropertyChangeEvent(this,"DELEGATED_EVENT", null, receivedEvent). So that the listeners can follow the chain of events.
Addicionally i have a static method in an Util class which follow the events chain and returns the very first event, the one whick property is not "DELEGATED_EVENT"
来源:https://stackoverflow.com/questions/1605762/propertychangesupport-and-equals-method