HashSet操作注意
来源:互联网 发布:移动网络怎样优化 编辑:程序博客网 时间:2024/04/30 21:26
使用HashSet的时候,会遇到一个很有意思的情况,大家看如下的代码:
1、定义User实体:重写hashCode和equals方法,具体什么功能,这边不做详细的介绍。
package com.enson.model;public class User {private int age ;private String name ;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;User other = (User) obj;if (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}2、测试代码:
package test;import java.util.HashSet;import java.util.Set;import com.enson.model.User;public class HashSetTest {public static void main(String[] args) {Set<User> set = new HashSet<User>();User user1 = new User();user1.setAge(20);user1.setName("enson");set.add(user1);User user2 = new User();user2.setAge(10);user2.setName("chan");set.add(user2);System.err.println(set.size());}}
如果在输出之前对set做remove操作呢:
set.add(user2);set.remove(user1);System.err.println(set.size());
3、看下面有意思的情况:
<pre name="code" class="java">set.add(user2);user1.setAge(30);set.remove(user1);System.err.println(set.size());
请你猜测一下,现在输出的结果是?
===========================================================================================
其实现在输出的结果仍然为:2
这是一个比较有意思的情况。当我们用HashSet进行存储对象时候,就会出现这样的情况。
想知道具体的原因,我们得从java源码的角度进行分析:
查看HashSet源码:
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable{ static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object(); /** * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has * default initial capacity (16) and load factor (0.75). */ public HashSet() {map = new HashMap<E,Object>(); }
我们可以看到,这边内部的实现其实是实例化一个HashMap
对于hashset的add方法:
public boolean add(E e) {return map.put(e, PRESENT)==null; } public boolean remove(Object o) { return map.remove(o)==PRESENT; }
其实际的操作是hashmap的put和remove方法
查看HashMap:
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
这边可以看到,当添加的时候,HashMap其实是根据hashcode和equals方法来判断是否是同一个对象。这样就明白了。
当set进行remove的时候,其实也是根据hashcode和equals方法来判断。当作user1.setAge(30);更改的时候,user1这个对象已经变了,与存在HashSet当中的user1已经不是同一个对象了,再remove的时候,根据变化了的user1来查找,其实已经是查找不到了。这样就导致remove失败。
再看一个意思的情况:
set.add(user2);user1.setAge(20);set.remove(user1);System.err.println(set.size());
如果将年龄仍然设置为20,这样得到的结果,相信大家都应该知道的。具体结果是什么?
- HashSet操作注意
- hashcode重写,hashSet操作
- Redis---hashset数据类型操作
- redis系列---hashset操作命令
- HashSet
- Hashset
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- HashSet
- ctrl+z 和 ctrl+c的关系
- tomcat下加载运行同一个复制项目错误
- oracle表空间类型
- gtest-1.60.zip在linux下的编译与简单测试
- 深入理解计算机系统 学习小结
- HashSet操作注意
- SQL Server复制入门
- 猴子分食桃子 ARM 汇编实现
- kill - 终止进程/发送信号
- How Tomcat works - Session Manager(base on Tomcat4)
- linux下gtest
- ASP中连接Access数据库App.config的配置
- 图片缓存实现策略分析
- 女方妈妈和男方爸爸这样告诉即将结婚的儿女