集合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方 ...
随机推荐
- activity生命周期的onPause和onStop
搞了这么长时间的android开发,却对一些基础的东西一直模棱两可...就比方这个onPause和onStop. 假设从一个界面,跳到还有一个界面,那么是调用哪个呢? 经过我的实验.搞清楚了.onPa ...
- bzoj3262: 陌上花开(cdq分治+树状数组)
3262: 陌上花开 题目:传送门 题解: %%%cdq分治 很强大的一个暴力...感觉比分块高级多了 这道题目就是一个十分经典的三维偏序的例题: 一维直接暴力排序x 二维用csq维护y 三维用树状数 ...
- HD-ACM算法专攻系列(13)——How Many Fibs?
问题描述: 源码: import java.math.BigInteger; import java.util.*; public class Main { //主函数 public static v ...
- Golang 中的 面向对象: 方法, 类, 方法继承, 接口, 多态的简单描述与实现
前言: Golang 相似与C语言, 基础语法与C基本一致,除了广受争议的 左花括号 必须与代码同行的问题, 别的基本差不多; 学会了C, 基本上万变不离其宗, 现在的高级语言身上都能看到C的影子; ...
- rsyslog 存储到 mysql
输出Host1/2的系统日志, 记录到mysql服务器数据库中, 并发布loganalyzer 结构关系如下图: 思路: 通过远程连接mysql, 使得rsyslog的log记录能够写入到mysql中 ...
- 织梦(dedecms)循环调用多级子栏目如二级栏目下三级栏目
本文是关于织梦DedeCMS调用多级子栏目的,拿来分享下. 后台已经建好栏目,对于产品展示栏 栏目导航如下图所示: 复制代码 代码如下: {dede:channelartlist cacheid=' ...
- javascript 继承之拷贝,原型,类式
// 拷贝继承,在子类内调用父类并修正this指向,再通过for in 拷贝父类的方法实现继承,具体实现如下代码 : function Tab(){//父类构造函数 this.name='aaa'; ...
- CSS常用样式--background
CSS background 属性 参考:W3school- CSS background 所有浏览器都支持 background 属性,其简写形式,在一个声明中设置所有的背景属性,各属性需按顺序,语 ...
- angular.js和vue.js中实现函数去抖(debounce)
问题描述 搜索输入框中,只当用户停止输入后,才进行后续的操作,比如发起Http请求等. 学过电子电路的同学应该知道按键防抖.原理是一样的:就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用 ...
- myssql数据库表名转驼峰 - PLAY - ITeye博客
原文:myssql数据库表名转驼峰 - PLAY - ITeye博客