HashSet

首先来看下HashSet的add()这个方法的源代码:

public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

由此可知HashSet的值是存储在一个Map的key里面的,而正好Map的key是不能重复的,以下是HashSet的部分源码:

 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>();
} public Iterator<E> iterator() {
return map.keySet().iterator();
} public int size() {
return map.size();
}

接着再看看HashMap里的put()方法是如何判断值是否重复的,以下是HashMap的put()源码:

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;
}

关键这句:if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

它先进行了hashCode的判断,如果hashCode相等再接着使用==来判断传入的对象的引用地址是否相等及使用传入对象的equals()方法来进行判断。

接着再看看HashSet的contains()方法的源码:

public boolean contains(Object o) {
return map.containsKey(o);
}

调用的是Map的containsKey()方法,以下是HashMap的containsKey()源码:

public boolean containsKey(Object key) {
return getEntry(key) != null;
} final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k)))) 和put()方法的判断是一样的。

TreeSet
看看TreeSet的add()方法的源码:
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}

它也同样是由一个Map的key来进行存储,看看这个Map:

/**
* The backing map.
*/
private transient NavigableMap<E,Object> m;

接着看看TreeSet的构造函数:

TreeSet(NavigableMap<E,Object> m) {
this.m = m;
} public TreeSet() {
this(new TreeMap<E,Object>());
}

TreeSet的无參构造函数里实例化了一个TreeMap对象,下面看看这个TreeMap对象:

public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{ private final Comparator<? super K> comparator; public TreeMap() {
comparator = null;
} public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
//其他略...
}
public interface NavigableMap<K,V> extends SortedMap<K,V>

接着看这个TreeMap的put()方法:

public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
// TBD:
// 5045147: (coll) Adding null to an empty TreeSet should
// throw NullPointerException
//
// compare(key, key); // type check
root = new Entry<K,V>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<K,V>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}

TreeMap存储的对象是会进行排序的,所以存储的对象都必须实现Comparable接口。

TreeMap先判断Comparator对象是否为空,不为空则使用当前的Comparator对象的compare方法来进行比较排序,若发现compareTo返回的值为0,则认为这两个对象是重复的了,然后覆盖原来的value;如果Comparator对象为空,则使用集合对象实现的Comparable接口的compareTo方法来进行比较排序,同样地当返回值是0时就认为对象重复,然后覆盖原来的value。

 

Set的非重复判断是根据什么判断的的更多相关文章

  1. linux shell脚本查找重复行/查找非重复行/去除重复行/重复行统计

    转自:http://blog.sina.com.cn/s/blog_6797a6700101pdm7.html 去除重复行 sort file |uniq 查找非重复行 sort file |uniq ...

  2. sort关于去除重复/查找非重复/查找重复/统计

    去除重复sort file |uniq   查找非重复 sort file | uniq -u   查找重复 sort file | uniq -d   统计 sort file | uniq -c

  3. MySQL(15):Select-distinct(返回非重复的记录)

    1. 查询所有记录 和 查询 非重复记录 语法: SELECT    [ALL | DISTINCT ] All:返回所有记录 Distinct:返回非重复记录 针对获得的记录内的字段生效.   2. ...

  4. leecode第二天-使用异或找出数组中的非重复元素

    leecode题目描述如下: 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 思路: 最开始想到的是使用排序,排序之后就很容易找到非重复元素了. ...

  5. [讲解]sql except和intersect运算符(比拟两个或多个select语句的结果并前去非重复值)

    图 1 UNION 中若有重复的行,会被移除,只留下一个 1.简介 EXCEPT和INTERSECT运算符使您可以比较两个或多个SELECT语句的结果并返回非重复值. 2.区别 EXCEPT运算符返回 ...

  6. SSAS 非重复计数

    在SSAS设计时,对商品编号列非重复计数:

  7. 判断密码是否可见/判断登录的状态/判断在form表单中 定义rules规则验证(iview)

    一: 判断密码是否可见判断:type="visiblePassword ? 'text' : 'password'" 是否为false 或者 true 密码为输入框或者文本框点击眼 ...

  8. dfs 全排列 使用交换——含重复元素和非重复元素

    15. 全排列 中文 English 给定一个数字列表,返回其所有可能的排列. 样例 样例 1: 输入:[1] 输出: [ [1] ] 样例 2: 输入:[1,2,3] 输出: [ [1,2,3], ...

  9. mysql删除重复记录,只保留最大ID的记录(非重复也保留)

    目前网上搜索的删除重复记录,大部分都是where子查询,本人感觉看上去不美观,故亲自手写了一个,如下: delete from mst_sku using mst_sku,(  select dist ...

随机推荐

  1. nginx_rewrite规则介绍

    rewrite功能就是,使用nginx提供的全局变量或自己设置的变量,结合正则表达式和标志位实现url重写以及重定向.rewrite只能放在server{},location{},if{}中,并且只能 ...

  2. python logger日志

    直接上代码 import logging import logging.handlers import datetime import time import threading from conf. ...

  3. for循环,字典遍历(二)

    #通过列表值,定义一个字典,来获取key和value str_list = [1,3,5,7,9,'i',9,'o',7,'i'] str_dict = {} for i in str_list: # ...

  4. 【Redis】二、Redis高级特性

    (三) Redis高级特性   前面我们介绍了Redis的五种基本的数据类型,灵活运用这五种数据类型是使用Redis的基础,除此之外,Redis还有一些特性,掌握这些特性能对Redis有进一步的了解, ...

  5. Python的/整除

    在python3和python2里,正整数的/结果是一样的,但是负数的整除却有区别 比如python3中,-1/2是等于0的,c/c++的结果也是这样, 但在python2中,-1/2确是-1,想要得 ...

  6. jet flow in a combustion chamber

    Table of Contents 1. contacts 2. Paper digest 2.1. LES vs. RANS 2.2. Dynamics of Transient Fuel Inje ...

  7. 洛谷 1328 生活大爆炸版石头剪刀布(NOIp2014提高组)

    [题解] 简单粗暴的模拟题. #include<cstdio> #include<algorithm> #include<cstring> #define LL l ...

  8. 18年多校-1002 Balanced Sequence

    >>点击进入原题测试<< 思路:自己写没写出来,想不通该怎么排序好,看了杜神代码后补题A掉的.重新理解了一下优先队列中重载小于号的含义,这里记录一下这种排序方式. #inclu ...

  9. 调试pcb板子的步骤

    在从外边焊回来的板子中查找问题的时候,如果只是简单的 一通乱调,很有可能一下子就调好了,但是大多数的时候是调了半天,不知道接下来该如何进行,因此,严格的按照步骤走,是个不错的想法: 1.拿到板子的第一 ...

  10. linux 简单实用小操作

    mysql改密码 通过root以后,(root密码忘记就没法了) alter user username@'%' identified by 'password' 端口被占用 sudo fuser - ...