Java 如何从类中的值更新HashMap键?
我正在尝试动态更新HashMap中的键 我已经创建了一个类的实例,并设置了从该类获取值的键 当我更新类中的值时,我试图获取要更改的键的值。我尝试为其执行此操作的程序有多个大型哈希映射。但是,我已将其简化为下面的示例 主类 当我更新类中的值时,HashMap中的键不会改变 我想做的是可能的吗?如果不是,我怎么能做到这一点呢?如果你想让地图在修改其他类对象的id时自动更新,那么你需要自己编写代码 除非映射和对象紧密耦合,否则应保持逻辑解耦,例如通过实现属性更改跟踪 我建议围绕Java运行时库中的类构建它 其他类 首先,您需要启用属性更改跟踪 我在这个答案的末尾添加了name属性以改进测试代码输出Java 如何从类中的值更新HashMap键?,java,hashmap,Java,Hashmap,我正在尝试动态更新HashMap中的键 我已经创建了一个类的实例,并设置了从该类获取值的键 当我更新类中的值时,我试图获取要更改的键的值。我尝试为其执行此操作的程序有多个大型哈希映射。但是,我已将其简化为下面的示例 主类 当我更新类中的值时,HashMap中的键不会改变 我想做的是可能的吗?如果不是,我怎么能做到这一点呢?如果你想让地图在修改其他类对象的id时自动更新,那么你需要自己编写代码 除非映射和对象紧密耦合,否则应保持逻辑解耦,例如通过实现属性更改跟踪 我建议围绕Java运行时库中的类构
public final class OtherClass {
private final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private int id;
private String name;
public OtherClass(int id, String name) {
this.id = id;
this.name = name;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
public int getId() {
return this.id;
}
public void setId(int id) {
int oldId = this.id;
this.id = id;
this.pcs.firePropertyChange("id", oldId, id);
}
public String getName() {
return this.name;
}
public void setName(String name) {
String oldName = this.name;
this.name = name;
this.pcs.firePropertyChange("name", oldName, name);
}
@Override
public String toString() {
return "OtherClass[" + this.id + ", " + this.name + "]";
}
}
其他地图
接下来,您需要封装映射,以便正确处理属性更改侦听器
为了防止内存泄漏,在不再需要OtherMap时清除它非常重要,否则,对OtherMap中单个OtherMap对象的引用将使该地图和地图中的所有对象在内存中保持活动状态。为了帮助实现这一点,我将对象设置为可自动关闭的,这样它就可以与try-with-resources语句一起使用,并使代码分析器帮助突出显示关闭/清除映射的需要
final class OtherMap implements AutoCloseable {
private final PropertyChangeListener listener = this::onPropertyChange;
private Map<Integer, OtherClass> map = new HashMap<>();
public OtherMap() {
}
public Set<Integer> keys() {
return Collections.unmodifiableSet(this.map.keySet());
}
public Collection<OtherClass> values() {
return Collections.unmodifiableCollection(this.map.values());
}
public OtherClass get(int id) {
return this.map.get(id);
}
public OtherClass add(OtherClass other) {
OtherClass prev = this.map.put(other.getId(), other);
if (prev != null)
prev.removePropertyChangeListener(this.listener);
other.addPropertyChangeListener(this.listener);
return prev;
}
public OtherClass remove(int id) {
OtherClass other = this.map.remove(id);
if (other != null)
other.removePropertyChangeListener(this.listener);
return other;
}
public void clear() {
this.map.values().forEach(other -> other.removePropertyChangeListener(this.listener));
this.map.clear();
}
private void onPropertyChange(PropertyChangeEvent evt) {
if (! "id".equals(evt.getPropertyName()))
return;
Integer oldId = (Integer) evt.getOldValue();
Integer newId = (Integer) evt.getNewValue();
if (oldId.equals(newId))
return;
OtherClass other = (OtherClass) evt.getSource();
if (this.map.putIfAbsent(newId, other) != null)
throw new IllegalStateException("Duplicate key");
if (! this.map.remove(oldId, other)) {
this.map.remove(newId);
throw new IllegalStateException();
}
}
@Override
public String toString() {
return this.map.toString();
}
@Override
public void close() {
clear();
}
}
输出
之前:{3=OtherClass[3,Eeny],5=OtherClass[5,Meeny],7=OtherClass[7,Miny],9=OtherClass[9,Moe]}
之后:{2=OtherClass[2,Meeny],3=OtherClass[3,Eeny],9=OtherClass[9,Moe]}
如果要在修改OtherClass对象的id时自动更新映射,则需要自己编写代码
除非映射和对象紧密耦合,否则应保持逻辑解耦,例如通过实现属性更改跟踪
我建议围绕Java运行时库中的类构建它
其他类
首先,您需要启用属性更改跟踪
我在这个答案的末尾添加了name属性以改进测试代码输出
public final class OtherClass {
private final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private int id;
private String name;
public OtherClass(int id, String name) {
this.id = id;
this.name = name;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
public int getId() {
return this.id;
}
public void setId(int id) {
int oldId = this.id;
this.id = id;
this.pcs.firePropertyChange("id", oldId, id);
}
public String getName() {
return this.name;
}
public void setName(String name) {
String oldName = this.name;
this.name = name;
this.pcs.firePropertyChange("name", oldName, name);
}
@Override
public String toString() {
return "OtherClass[" + this.id + ", " + this.name + "]";
}
}
其他地图
接下来,您需要封装映射,以便正确处理属性更改侦听器
为了防止内存泄漏,在不再需要OtherMap时清除它非常重要,否则,对OtherMap中单个OtherMap对象的引用将使该地图和地图中的所有对象在内存中保持活动状态。为了帮助实现这一点,我将对象设置为可自动关闭的,这样它就可以与try-with-resources语句一起使用,并使代码分析器帮助突出显示关闭/清除映射的需要
final class OtherMap implements AutoCloseable {
private final PropertyChangeListener listener = this::onPropertyChange;
private Map<Integer, OtherClass> map = new HashMap<>();
public OtherMap() {
}
public Set<Integer> keys() {
return Collections.unmodifiableSet(this.map.keySet());
}
public Collection<OtherClass> values() {
return Collections.unmodifiableCollection(this.map.values());
}
public OtherClass get(int id) {
return this.map.get(id);
}
public OtherClass add(OtherClass other) {
OtherClass prev = this.map.put(other.getId(), other);
if (prev != null)
prev.removePropertyChangeListener(this.listener);
other.addPropertyChangeListener(this.listener);
return prev;
}
public OtherClass remove(int id) {
OtherClass other = this.map.remove(id);
if (other != null)
other.removePropertyChangeListener(this.listener);
return other;
}
public void clear() {
this.map.values().forEach(other -> other.removePropertyChangeListener(this.listener));
this.map.clear();
}
private void onPropertyChange(PropertyChangeEvent evt) {
if (! "id".equals(evt.getPropertyName()))
return;
Integer oldId = (Integer) evt.getOldValue();
Integer newId = (Integer) evt.getNewValue();
if (oldId.equals(newId))
return;
OtherClass other = (OtherClass) evt.getSource();
if (this.map.putIfAbsent(newId, other) != null)
throw new IllegalStateException("Duplicate key");
if (! this.map.remove(oldId, other)) {
this.map.remove(newId);
throw new IllegalStateException();
}
}
@Override
public String toString() {
return this.map.toString();
}
@Override
public void close() {
clear();
}
}
输出
之前:{3=OtherClass[3,Eeny],5=OtherClass[5,Meeny],7=OtherClass[7,Miny],9=OtherClass[9,Moe]}
之后:{2=OtherClass[2,Meeny],3=OtherClass[3,Eeny],9=OtherClass[9,Moe]}
哈希映射不会以这种方式重新调整其键。键是5,因为这就是您向映射添加值时的ID;对于一个好的散列,应该是O1。好问题。HashMaps不会以这种方式重新调整它们的键。键是5,因为这就是您向映射添加值时的ID;对于一个好的散列,应该是O1。好问题。
OtherClass eeny = new OtherClass(3, "Eeny");
OtherClass meeny = new OtherClass(5, "Meeny");
OtherClass miny = new OtherClass(7, "Miny");
OtherClass moe = new OtherClass(9, "Moe");
OtherMap otherMap = new OtherMap();
otherMap.add(eeny);
otherMap.add(meeny);
otherMap.add(miny);
otherMap.add(moe);
System.out.println("Before: " + otherMap);
meeny.setId(2);
otherMap.remove(miny.getId());
miny.setId(4);
System.out.println("After: " + otherMap);