zoukankan      html  css  js  c++  java
  • Java HashSet的元素内容变化导致的问题

    概述

    HashSet元素引用的对象的内容发生变化,会导致“元素不属于集合”的问题。事实上这个元素还在集合里,但是调用contains方法进行判断,得到的结果却是false。

    正文

    关于变化

    这里所讲的变化是指元素引用的对象的内容的变化,但是对象还是这个对象。比如我们定义如下的field

    private Set<Set<Integer>> cache = new HashSet<Set<Integer>>();

    我们计划cache里的每一个元素都是一个Set<Integer>的集合。如果我们取出cache的一个元素,然后往这个元素集合中添加一个Integer元素。对于cache来说,这个元素还是这个元素,但是它的内容已经变化了。

    关于校验标准

    /**
     * 校验.<br>
     * 从集合中取出的元素反而不属于该集合,则为无效.
     * @return
     */
    private boolean validate() {
        boolean flag = true;
        for ( Set<Integer> ele : cache ) {
            if (!cache.contains(ele)) {
                flag = false;
                System.out.println("无效的元素:" + ele);
            }
        }
        
        return flag;
    }

    测试

    我们分为三个测试用例:数据初始化测试、直接更新测试、移除新增测试。

    一、数据初始化测试

    1. 数据初始化

    /**
     * 初始化数据.
     */
    private void init() {
        Integer[][] data = {{1, 2}, {3, 4}, {5}};
        for (Integer[] ele : data) {
            List<Integer> eleList = Arrays.asList(ele);
            Set<Integer> eleSet = new HashSet<Integer>(eleList.size());
            eleSet.addAll(eleList);
            
            cache.add(eleSet);
        }
        
        System.out.println(cache);
    }

    2. 测试

    @Test
    public void testInit() {
        init();
        boolean flag = validate();
        System.out.println("对初始化的数据进行校验,结果:" + flag);
    }

    3. 输出结果

    [[2, 1], [5], [4, 3]]
    对初始化的数据进行校验,结果:true

    二、直接更新测试

    1. 更新的方法

    /**
     * 直接修改.
     */
    private void update() {
        for (Set<Integer> ele : cache) {
            if (ele.contains(5)) {
                ele.add(6);
                break;
            }
        }
        
        System.out.println(cache);
    }

    2. 测试

    @Test
    public void testUpdate() {
        init();
        update();
        
        boolean flag = validate();
        System.out.println("对直接修改的数据进行校验,结果:" + flag);
    }

    3. 输出结果

    [[2, 1], [5], [4, 3]]
    [[2, 1], [6, 5], [4, 3]]
    无效的元素:[6, 5]
    对直接修改的数据进行校验,结果:false

    三、移除新增测试

    1. 移除新增

    /**
     * 移除添加.
     */
    private void removeThenAdd() {
        for (Set<Integer> ele : cache) {
            if (ele.contains(5)) {
                cache.remove(ele);
                ele.add(6);
                cache.add(ele);
                break;
            }
        }
        
        System.out.println(cache);
    }

    2. 测试

    @Test
    public void testRA() {
        init();
        removeThenAdd();
        
        boolean flag = validate();
        System.out.println("对移除添加的数据进行校验,结果:" + flag);
    }

    3. 输出结果

    [[2, 1], [5], [4, 3]]
    [[2, 1], [4, 3], [6, 5]]
    对移除添加的数据进行校验,结果:true

    结论

    我认为HashSet遍历元素和判断元素是否在集合中的机制是不同的,HashSet中的元素都有一个不同的hashcode,我们直接修改其中的元素,导致其内容和其hashcode对应不上,所以才会有上述的问题。

  • 相关阅读:
    Python挂载杂记
    Python Log的使用, 模块化
    Python实现图片长宽比例缩放和填充
    系统监控与硬盘
    linux基础三
    linux基础二
    linux基础一
    网络基础
    操作系统
    计算机硬件基础
  • 原文地址:https://www.cnblogs.com/ywjy/p/5073082.html
Copyright © 2011-2022 走看看