开发者社区> 问答> 正文

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

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

我已经创建了一个类的实例,并设置了密钥以从该类中获取值。

我试图在更新类中的值时获取要更改的键的值。我正在尝试执行的程序具有多个大型哈希图。但是,我将其简化为以下示例。

主班

import java.util.HashMap;

public class Main {

    public static void main(String[] args) {
        HashMap<Integer, String> hashMap = new HashMap<>();
        OtherClass otherClass = new OtherClass(5);

        hashMap.put(otherClass.getId(), "a string");
        otherClass.setId(0);   // update value in class

        System.out.println(hashMap.keySet());   // outputs 5 not 0
    }
}

其他班

class OtherClass {
    int id;

    OtherClass (int id) {
        this.id = id;
    }

    void setId(int id) {
        this.id = id;
    }

    int getId() {
        return id;
    }
}

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

我正在尝试做的事情甚至可能吗?如果没有,我怎么能做到这一点?

问题来源:Stack Overflow

展开
收起
montos 2020-03-25 19:22:11 523 0
1 条回答
写回答
取消 提交回答
  • 如果你想Map自动更新时id一个的OtherClass对象被修改,那么你需要编写的代码为你自己。

    除非地图和对象紧密耦合,否则应保持逻辑分离,例如,通过实现属性更改跟踪。

    我建议围绕PropertyChangeSupportJava Runtime Library中的类构建它。

    其他类 首先,您需要启用属性更改跟踪。

    我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 + "]";
        }
    }
    

    接下来,您需要封装,Map以便可以正确处理属性更改侦听器。

    为了防止内存泄漏,重要的是要clear()在OtherMap当不再需要它,否则,以一个单一的参考OtherMap对象,它是在OtherMap将保持在map和所有在map中的对象在内存活。为了解决这个问题,我创建了object AutoCloseable,以便可以将其与try-with-resources语句一起使用,并使代码分析器帮助强调需要关闭/清除Map。

    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();
        }
    }
    

    测试

    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);
    

    输出量

    Before: {3=OtherClass[3, Eeny], 5=OtherClass[5, Meeny], 7=OtherClass[7, Miny], 9=OtherClass[9, Moe]}
    After: {2=OtherClass[2, Meeny], 3=OtherClass[3, Eeny], 9=OtherClass[9, Moe]}
    
    

    回答来源:Stack Overflow

    2020-03-25 19:24:32
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载