如何正确地为Map.Entry添加值更改侦听器?



我目前正在进行的一个项目要求我确保在循环通过地图的条目时,如果条目。调用setValue时,它将触发一个值更改事件。我认为我可以尝试将侦听器添加到.put方法上Map类的扩展中。我的问题是,条目被更改会触发map的put方法中的侦听器吗?或者我将被迫延长地图。入口类和坚持监听逻辑到它的setValue方法?

如果这个问题是愚蠢的,我提前道歉-我刚开始以这种方式使用地图,到目前为止我看到的很多信息只导致扩展地图本身,这似乎最简单,但我不知道它是否涵盖我的情况。

必要时可以使用PropertyChangeSupport类。这使得管理propertyChanges非常容易。这里没什么可说的。希望侦听更改的各方将其侦听器注册到地图中。然后,当映射修改该值时,支持将向所有侦听器触发一个事件。在Event类中返回的值可以更改为选择的值。

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashMap;
public class PropertyChangeDemo implements PropertyChangeListener {

public static void main(String[] args) {
// leave static context of main
new PropertyChangeDemo().start();
}
public void start() {
MyMap<String,Integer> map = new MyMap<>();
map.addMapListener(this);
map.put("B",20);
map.put("B",99);
map.put("A",44);

map.entrySet().forEach(System.out::println);
}

打印

source = map
oldValue = null
newValue = 20
source = map
oldValue = 20
newValue = 99
source = map
oldValue = null
newValue = 44
A=44
B=99

用于演示的监听器。

public void propertyChange(PropertyChangeEvent pce) {
System.out.println("source = " + pce.getPropertyName());
System.out.println("oldValue = " + pce.getOldValue());
System.out.println("newValue = " + pce.getNewValue());
}

}

修改后的类

class MyMap<K,V> extends HashMap<K,V> {

private PropertyChangeSupport ps = new PropertyChangeSupport(this);
// method to add listener
public void addMapListener(PropertyChangeListener pcl) {
ps.addPropertyChangeListener(pcl);
}

@Override 
public V put(K key, V value) {
V ret = super.put(key,value);
ps.firePropertyChange("map", ret, value);
return ret;
}
}   

注意:在这个简单的解决方案中可能遗漏了一些问题。在投入生产使用前应进行测试。首先,有许多不同的方法来设置Entry's值。只有当put被用户调用或映射本身间接调用时才会这样做。

Map.Entry只是一个接口,所以当然可以编写一个实现来触发注册到它的EventListener实例或拥有的Map实例的值更改事件。

但是我看不出如何说服任何现有的Map接口实现使用Entry的新实现…

所以你最终会创建自己的Map实现…

或者,当你需要改变侦听器只有当迭代条目设置,您可以覆盖的方法Map.entrySet()Map的适当的实现,它将返回一个修改版的SetSet.iterator()——调整的方式方法返回一个Iterator实例的方法Iterator.next()返回您的实现Map.Entry(包装原始和委派方法之一…)的setValue()方法将触发值改变监听器。

像这样:

public class MyMapEntry<K,V> implements Map.Entry<K,V>
{
private final Map.Entry<K,V> m_Wrapped;
private final ChangeListener m_Listener;

public MyMapEntry( ChangeListener listener, Map.Entry<K,V> entry ) 
{ 
m_Listener = listener; 
m_Wrapped = entry; 
}

@Override
public void setValue( V value )
{
var event = new ChangeEvent( this, getValue(), value );
m_Wrapped.setValue( value );
m_Listener.sendEvent( event );
}
… // Implement the other methods
}
public class MyIterator<Map.Entry<K,V>> implements Iterator<Map.Entry<K,V>>
{
private final Iterator<Map.Entry<K,V>> m_Iterator;
private final ChangeListener m_Listener;
public MyIterator( final ChangeListener listener, final Iterator<Map.Entry<K,V>> iterator )
{
m_Listener = listener;
m_Iterator = iterator;
}
public Map.Entry<K,V> next()
{
return new MyMapEntry( m_Listener, m_Iterator.next() );
}
… // Delegation for all the other methods 
}
public class MySet<Map.Entry<K,V>> extends HashSet<Map.Entry<K,V>>  
{
private final ChangeListener m_Listener;
public MySet( ChangeListener listener, Set<Map.Entry<K,V>> other )
{
super( other );
m_Listener = listener;
}
@Override
public Iterator<Map.Entry<K,V>> iterator()
{
return new MyIterator( m_Listener, super.iterator() ); 
}
}     
public class MyMap<K,V> extends HashMap<K,V>
{
private final ChangeListener m_Listener;
public MyMap( ChangeListener listener ) 
{ 
super();
m_Listener = listener; 
}

@Override
public Set<Map.Entry<K,V>> entrySet()
{
return new MySet( listener, super.entrySet() );
} 
}

这段代码只是一个草图,在运行之前可能需要一些修复!

复制MyMap.entrySet()中的条目集将您的条目集与原始条目集解耦;对映射结构的更改将不再反映到您的集合中-但是对键值和值值的更改仍然会影响您的集合。

最新更新