集合HashSet的使用
集合中的HashSet底层是通过Hash表实现,HashSet的特点是元素唯一,但用到Hash表就跟hashCode()有了密不可分的联系,所以HashSet的唯一性是通过hashCode()方法来保证,当然光有HashCode()还不够,还有equals()也用到。从底层(HashMap的put()方法)实现代码来看,就可以清楚地看到这一点。
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
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的put()方法源码。那么HashSet到底是如何保证元素的唯一性,还是通过例子来说明这一点。同样,还是以HashSet存储自定义对象为例,先创建一个Person类,成员:name、age、无参、有参构造及getters和setters。
package cn.dolphin;
public class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
这里先没有重写继承自Object类的hashCode()和equals()方法。
package cn.dolphin; import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; public class HashSetDemo {
public static void main(String[] args) {
//创建集合对象
Set<Person> set = new HashSet<>();
//创建对象元素
Person p1 = new Person("诸葛亮",39);
Person p2 = new Person("赵子龙",36);
Person p3 = new Person("关云长",38);
Person p4 = new Person("关云长",38);
Person p5 = new Person("关云长",38);
//将对象元素添加到集合
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
//使用iterator()对集合遍历
for (Iterator<Person> it = set.iterator(); it.hasNext();) {
Person p = it.next();
System.out.println(p);
}
}
}
运行程序的结果看到[关云长,38]出现了三次,这说明没有保证元素的唯一。现在我们在Person类中重写hashCode()和equals()。使用eclipse直接右键"Source->Generate hashCode() and equals()..."自动生成代码。
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Person))
return false;
Person other = (Person) 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;
}
再次运行程序,看到结果中[关云长,38]只出现了一次,说明已经对相同元素进行了过滤。再回过头来看看上面的源代码,里面的if语句"if (e.hash == hash && ((k = e.key) == key || key.equals(k)))"使用的"&&",这个逻辑运算符的使用,还是有必要在这里啰嗦一下,只有"&&"的左边为true才会对右边进行判断,左边如果false,就不再看右边,这不禁使我想起一道面试题,扯远了,这个最后说。那么"&&"用在这里就意味着,如果左边的hashCode()判断false,会直接添加元素,不用再判断equals(),如果左边true,才会继续判断equals()。因为"&&"具有短路功能,这就是HashSet保证元素唯一的原理。
下面说说刚才提到的面试题。
int x = 1, y = 1;
if(x++ > 3 && ++y > 3){
++x;
y++;
}
System.out.println(x);
System.out.println(y);
集合HashSet的使用的更多相关文章
- Java集合 -- HashSet 和 HashMap
HashSet 集合 HashMap 集合 HashSet集合 1.1 Set 接口的特点 Set体系的集合: A:存入集合的顺序和取出集合的顺序不一致 B:没有索引 C:存入集合的元素没有重复 1. ...
- java集合-HashSet
HashSet 概述 对于 HashSet 而言,它是基于 HashMap 实现的,底层采用 HashMap 来保存元素,所以如果对 HashMap 比较熟悉了,那么学习 HashSet 也是很轻松的 ...
- Java 集合 - HashSet
一.源码解析 public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable ...
- Java集合---HashSet的源码分析
一. HashSet概述: HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set 的迭代顺序:特别是它不保证该顺序恒久不变.此类允许使用null元素. 二. ...
- Set集合——HashSet、TreeSet、LinkedHashSet(2015年07月06日)
一.Set集合不同于List的是: Set不允许重复 Set是无序集合 Set没有下标索引,所以对Set的遍历要通过迭代器Iterator 二.HashSet 1.HashSet由一个哈希表支持,内部 ...
- 哈希集合——hashSet
/** 哈希集合特点:存取顺序不确定,同一个哈希值的位置可以存放多个元素, 哈希集合存放元素的时候是先判断哈希地址值:hashCode()是否相同,如果不同 ...
- ava集合---HashSet的源码分析
一.HasnSet概述 Hashset实现set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set的迭代顺序.特别是它不保证该顺序恒久不变.此类允许使用Null元素 一.HasnSe ...
- java集合-HashSet源码解析
HashSet 无序集合类 实现了Set接口 内部通过HashMap实现 // HashSet public class HashSet<E> extends AbstractSet< ...
- 集合-HashSet
参考博客:https://www.cnblogs.com/runwulingsheng/p/5208762.html https://www.cnblogs.com/ysocean/p/6555373 ...
- 基于散列的集合 HashSet\HashMap\HashTable
HashSet\HashMap\HashTable 1 基于散列的集合 2 元素会根据hashcode散列,因此,集合中元素的顺序不一定与插入的顺序一致. 3 根据equals方法与hashCode方 ...
随机推荐
- bzoj2150: 部落战争(匈牙利)
2150: 部落战争 题目:传送门 题解: 辣鸡数据..毁我AC率 先说做法,很容易就可以看出是二分图匹配的最小路径覆盖(可能是之前不久刚做过类似的题) 一开始还傻逼逼的去直接连边然后准备跑floyd ...
- php 设计模式之工厂模式
php 设计模式之工厂模式 简介: 在开发大型系统过程中,往往会出现这样一种情况: 我有一部分基础数据,是类classA是从数据库A读取出来的,其他很多的功能都是基于这个基础数据来操作的.现在呢,我想 ...
- 解决django.db.utils.InternalError: (1049, "Unknown database 'exam_db'")
先检查seeting数据库配置DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'eaxm_db', ' ...
- BZOJ 1101 莫比乌斯函数+分块
思路: 题目中的gcd(x,y)=d (x<=a,y<=b)可以转化成 求:gcd(x,y)=1 (1<=x<=a/d 1<=y<=b/d) 设 G(x,y)表示x ...
- css文字换行问题white-space:pre-line或者white-space:pre-wrap,解决word-wrap:break-word解决不了的
想让文字换行必须要写的那几个css样式就略过了.当一行文字是数字或字母时或者数字字母组合时会出现不换行局面,这时候加个word-wrap:break-word:就基本可以解决但是有种情况是它解决不了的 ...
- 大神js总结
http://www.cnblogs.com/tylerdonet/p/5543813.html http://www.codesec.net/list/8/
- centos下nginx配置
转自 http://www.linuxidc.com/Linux/2016-09/134907.htm 安装所需环境 Nginx 是 C语言 开发,建议在 Linux 上运行,当然,也可以安装 Wi ...
- php 基础------数组过滤
array_filter();过滤数组 语法: array_filter(array,callbackfunction); array 必写,规定要过滤的数组 callbackfunction 必写, ...
- php对excel导入导出的支持
闲话不多说了,大家直接进入主题 php对excel的导入: 1.为程序添加一个form表单,为form标签添加“enctype="multipart/form-data"”属性 ...
- [APIO2014]回文串(回文自动机)
题意 给你一个由小写拉丁字母组成的字符串 s.我们定义 s 的一个子串的存在值为这个子串在 s 中出现的次数乘以这个子串的长度. 对于给你的这个字符串 s,求所有回文子串中的最大存在值. |S|< ...