集合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方 ...
随机推荐
- apiCloud中实现头部与内容分离与操作规范,App头部header固定,头部与内容分离
官方案例 1.头部拆分成一个页面比如news-text <!doctype html> <html> <head> <meta charset="u ...
- HTTP学习记录
title: HTTP学习记录 toc: true date: 2018-09-21 20:40:48 HTTP协议,HyperText Transfer Protocol,超文本传输协议,是因特网上 ...
- 如何做到Ubuntu14.04下的mongdb远程访问?(图文详解)
不多说,直接上干货! 本教程详细指导大家如何开启并设置用户权限.MongoDB默认是没有开启用户权限的,如果直接在公网服务器上如此搭建MongoDB,那么所有人都可以直接访问并修改数据库数据了. 其实 ...
- C++之易混淆知识点一-----static详解
1.const.mutable与volatile的区别:const表明内存被初始化以后,程序将不能对它进行修改.volatile则表明,即使程序代码没有对内存单元进行修改,但是里面的值也可能会发生变化 ...
- [转帖]关于Xilinx下Micro_Blaze中UartLite232外设的使用
来源:https://blog.csdn.net/shen_you/article/details/78713746
- C语言-实现字符串倒序输出
方法1: Action(){//倒序输出 char *src="abcdefgh123"; char *desc; desc=(char *)malloc(100*sizeof(c ...
- js函数参数理解
eg: function setName(obj){ obj.name = "Nicholas"; obj = new Object(); obj.name = "Gre ...
- socket网络编程登录实现及多客户端和服务端的数据交互
一.TCP/IP 客户端 package com.demo.entity; import java.io.Serializable; public class UserInfo implements ...
- 关于Vue中父子组件相互传值
Header为子组件,Home为父组件,通过子组件调用父组件 运行结果如下 下面是父组件调用子组件的案例 通过button按钮的click事件 图一是父组件Home中的run方法,图二是msg和fun ...
- 《Craking the Coding interview》python实现---01
###题目:给定一个字符串,判断其中是否有重复字母###思路:将重复的字符放入到list中,并进行计数统计###实现:伪代码.函数.类实现###伪代码:string=s #给定的字符串list=[] ...