HashSet源码分析1
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; public class SetTest {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("abc");
set.add("xyz");
set.add("abc"); for (Iterator<String> it = set.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}
查看add方法
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
查看map.put方法:
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
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;
}
关于set:当向Set集合中添加对象时,集合首先要计算出待添加对象的hashCode值,根据该值来得到一个位置,用于存放当前的对象。如果该位置没有对象存在,那么集合Set就会认为该对象在集合中不存在,直接添加进去。如果该位置已经有一个对象存在,接着将准备添加到集合中的对象与该位置上的对象进行equals方法比较,如果该equals方法返回false,那么集合认为该集合中不存在该对象的,再进行一次散列,将该对象放到散列后计算的地址里。如果equals方法返回true,那么集合认为该对象已经存在了,不会再将对象添加到集合中。
在上面的例子中我们的执行结果为:
true
true
false
abc
xyz
第三个abc插入失败了,原因就是String类型的字符串“abc”的hashcode是相等的而且equals也是相等的(equals方法使一个字符一个字符的进行比较)。
再看下面的例子:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; public class SetTest {
public static void main(String[] args) {
/* Set<String> set = new HashSet<>();
System.out.println(set.add("abc"));
System.out.println(set.add("xyz"));
System.out.println(set.add("abc")); for (Iterator<String> it = set.iterator(); it.hasNext();) {
System.out.println(it.next());
}*/
Set<People> set2 = new HashSet<>();
set2.add(new People("zhangsan"));
set2.add(new People("lisi"));
set2.add(new People("zhangsan"));
for(Iterator<People> it = set2.iterator();it.hasNext();){
System.out.println(it.next().getName());
}
}
}
class People{
String name;
public People(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
运行结果为:
lisi
zhangsan
zhangsan
同样是zhangsan却能添加两次。
如果想根据name来判断,修改代码如下:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; public class SetTest {
public static void main(String[] args) {
/*
* Set<String> set = new HashSet<>();
* System.out.println(set.add("abc"));
* System.out.println(set.add("xyz"));
* System.out.println(set.add("abc"));
*
* for (Iterator<String> it = set.iterator(); it.hasNext();) {
* System.out.println(it.next()); }
*/
/*
* String a = "abc"; String b = "abc"; System.out.println(a.hashCode());
* System.out.println(b.hashCode());
*/
Set<People> set2 = new HashSet<>();
set2.add(new People("zhangsan"));
set2.add(new People("lisi"));
set2.add(new People("zhangsan"));
for (Iterator<People> it = set2.iterator(); it.hasNext();) {
System.out.println(it.next().getName());
}
}
} class People {
String name; public People(String name) {
this.name = name;
} public String getName() {
return this.name;
} @Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof People) {
People people = (People) obj;
if(this.name.equals(people.getName()));
return true;
}
return false;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
}
执行结果为:
lisi
zhangsan
当重写equals方法时,必须要重写hashCode方法。如果一个类的两个对象,使用equals方法比较时返回true,那么这两个对象必须要具有相同的hashCode。
HashSet源码分析1的更多相关文章
- HashSet源码分析
在java集合中有一种集合Set(集),他有两个实现类,分别是HashSet,TreeSet.下面仔细分析HashSet源码. 看了HashSet的源码就会发现HashSet的底层实现是利用HashM ...
- 死磕 java集合之HashSet源码分析
问题 (1)集合(Collection)和集合(Set)有什么区别? (2)HashSet怎么保证添加元素不重复? (3)HashSet是否允许null元素? (4)HashSet是有序的吗? (5) ...
- 【Java入门提高篇】Day26 Java容器类详解(八)HashSet源码分析
前面花了好几篇的篇幅把HashMap里里外外说了个遍,大家可能对于源码分析篇已经讳莫如深了.别慌别慌,这一篇来说说集合框架里最偷懒的一个家伙——HashSet,为什么说它是最偷懒的呢,先留个悬念,看完 ...
- HashSet源码分析:JDK源码系列
1.简介 继续分析源码,上一篇文章把HashMap的分析完毕.本文开始分析HashSet简单的介绍一下. HashSet是一个无重复元素集合,内部使用HashMap实现,所以HashMap的特征耶继承 ...
- java.util.HashSet源码分析
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java. ...
- JAVA的HashSet源码分析
一.HashSet概述 HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set的迭代顺序:特别是它不保证该顺序恒久不变.此类允许使用null元素. 二.HashS ...
- Java集合之HashSet源码分析
概述 HashSet是基于HashMap来实现的, 底层采用HashMap的key来保存数据, 借此实现元素不重复, 因此HashSet的实现比较简单, 基本上的都是直接调用底层HashMap的相关方 ...
- HashSet源码分析 jdk1.6
Set的特点:Set元素无顺序,且元素不可以重复. 1.定义 public class HashSet<E> extends AbstractSet<E> implements ...
- HashSet源码分析2
package com.test1; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public ...
随机推荐
- Elasticsearch--集群管理_时光机&监控
目录 Elasticsearch时光机 创建快照存储库 清理:删除旧的快照 监控集群状态和健康度 集群健康度API 索引统计API 状态API 节点信息API 节点统计API 集群状态API 挂起任务 ...
- mysql中int(1)与int(10)的区别
INT[(M)] [UNSIGNED] [ZEROFILL] 普通大小的整数.带符号的范围是-2147483648到2147483647.无符号的范围是0到4294967295. INT(1) 和 I ...
- chown - 修改文件所有者和组别
总览 chown [options] user [:group] file... POSIX 选项: [-R] GNU 选项(最短格式): [-cfhvR] [--dereference] [--re ...
- 所有的工作目录 都要svn_开头,并且要进行svn同步,你能保证你不删除,你保证不了非你!
所有的工作目录 都要svn_开头,并且要进行svn同步,你能保证你不删除,你保证不了非你! 血的代价啊~
- 判断Exe(DLL)和符号文件是否匹配---验证模块和符号文件是否匹配的工具和方法
当我们进行程序调试时,有时调试器会直接告诉你符号文件不对,或则显示出的调用栈不对,当你怀疑符号文件不匹配时,如何确定呢? 如果是用windbg调试,请用 !chksym 模块名比如,匹配的时候 不匹 ...
- nginx配置实现负载均衡
一.负载均衡的作用 1.转发功能 按照一定的算法[权重.轮询],将客户端请求转发到不同应用服务器上,减轻单个服务器压力,提高系统并发量. 2.故障移除 通过心跳检测的方式,判断应用服务器当前是否可以正 ...
- css + 和 ~的区别
<style type="text/css"> h1 + p { margin-top:50px; color:red; } </style> <p& ...
- mybatis中<![CDATA[]]>的作用
此篇文章引自QH_JAVA的文章 在使用mybatis 时我们sql是写在xml 映射文件中,如果写的sql中有一些特殊的字符的话,在解析xml文件的时候会被转义,但我们不希望他被转义,所以我们要使用 ...
- 关于latch: cache buffers chains的sql优化
前段时间,优化了一些耗buffer比较多的sql,但是CPU使用率还是没下来 . 查看操作系统CPU使用率 查看awr,发现又有一条超级耗性能的sql冒出来了. 该SQL每次执行耗费3e多个buffe ...
- centos6基础优化
一.关闭SELinux功能 selinux功能太严苛,还是关闭了吧 法一:修改配置文件,永久生效 [root@web01 ~]# sed -i 's/SELINUX=enforcing/SELINUX ...