你的位置:首页 > Java教程

[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. 测试

@Testpublic 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. 测试

@Testpublic 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. 测试

@Testpublic 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对应不上,所以才会有上述的问题。