Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何从类中的值更新HashMap键?_Java_Hashmap - Fatal编程技术网

Java 如何从类中的值更新HashMap键?

Java 如何从类中的值更新HashMap键?,java,hashmap,Java,Hashmap,我正在尝试动态更新HashMap中的键 我已经创建了一个类的实例,并设置了从该类获取值的键 当我更新类中的值时,我试图获取要更改的键的值。我尝试为其执行此操作的程序有多个大型哈希映射。但是,我已将其简化为下面的示例 主类 当我更新类中的值时,HashMap中的键不会改变 我想做的是可能的吗?如果不是,我怎么能做到这一点呢?如果你想让地图在修改其他类对象的id时自动更新,那么你需要自己编写代码 除非映射和对象紧密耦合,否则应保持逻辑解耦,例如通过实现属性更改跟踪 我建议围绕Java运行时库中的类构

我正在尝试动态更新HashMap中的键

我已经创建了一个类的实例,并设置了从该类获取值的键

当我更新类中的值时,我试图获取要更改的键的值。我尝试为其执行此操作的程序有多个大型哈希映射。但是,我已将其简化为下面的示例

主类

当我更新类中的值时,HashMap中的键不会改变

我想做的是可能的吗?如果不是,我怎么能做到这一点呢?

如果你想让地图在修改其他类对象的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]} 如果要在修改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);