`
paldosfan
  • 浏览: 29391 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JAVA Set 不重复实现原理

 
阅读更多
Set 不重复实现原理
http://softbeta.iteye.com/blog/1185602

博客分类: java
java
Java中的set是一个不包含重复元素的集合,确切地说,是不包含e1.equals(e2)的元素对。Set中允许添加null。Set不能保证集合里元素的顺序。
在往set中添加元素时,如果指定元素不存在,则添加成功。也就是说,如果set中不存在(e==null ? e1==null : e.queals(e1))的元素e1,则e1能添加到set中。
下面以set的一个实现类HashSet为例,简单介绍一下set不重复实现的原理:
Java代码 
import java.util.HashSet; 
import java.util.Iterator; 
import java.util.Set; 
  
/**
* @version 1.0
* @author Oliver
* @since 1.0
*/ 
publicclass HashSetTest 

    //自定义MyString类 
    staticclass MyString{ 
        String value; 
  
        public MyString(String value) 
        { 
            this.value = value; 
        } 
    } 
    publicstaticvoid main(String[] args) 
    { 
        //创建一个HashSet对象 
        Set<Object> set = new HashSet<Object>(); 
        //创建连个String对象 
        String s1 = new String("a"); 
        String s2 = new String("a"); 
        //创建连个MyString对象 
        MyString s3 = new MyString("a"); 
        MyString s4 = new MyString("a"); 
        //添加元素 
        set.add(s1); 
        set.add(s2); 
        set.add(s3); 
        set.add(s4); 
        //看看对象的equals 
        System.out.println("s1.equals(s2):"+s1.equals(s2)); 
        System.out.println("s3.equals(s4):"+s3.equals(s4)); 
        //打印几个大小及里面的元素 
        System.out.println("set size:"+set.size()); 
        for(Iterator<Object> it=set.iterator();it.hasNext();){ 
            System.out.println(it.next()); 
        } 
    } 


运行程序,输出结果:
s1.equals(s2):true
s3.equals(s4):false
set size:3
oliver.examination.part1.HashSetTest$MyString@4f1d0d
a
oliver.examination.part1.HashSetTest$MyString@1fc4bec
也许你已经看出关键来了,没错就是equals方法。这么说还是不恰当,准确的说应该是equals和hashcode方法。
java.lnag.Object中对hashCode的约定:
1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
根据第一条,s1和s2返回的hashcode值是一样的。
在HashSet中,基本的操作都是有HashMap底层实现的,因为HashSet底层是用HashMap存储数据的。当向HashSet中添加元素的时候,首先计算元素的hashcode值,然后用这个(元素的hashcode)%(HashMap集合的大小)+1计算出这个元素的存储位置,如果这个位置位空,就将元素添加进去;如果不为空,则用equals方法比较元素是否相等,相等就不添加,否则找一个空位添加。
会后,附赠HashSet源码中文注释版,摘自javaeye:http://xifangyuhui.javaeye.com/blog/798796
Java代码 
public class HashSet<E>   
    extends AbstractSet<E>   
    implements Set<E>, Cloneable, java.io.Serializable   
{   
    static final long serialVersionUID = -5024744406713321676L;   
   
    // 底层使用HashMap来保存HashSet中所有元素。   
    private transient HashMap<E,Object> map;   
       
    // 定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。   
    private static final Object PRESENT = new Object();   
   
    /** 
     * 默认的无参构造器,构造一个空的HashSet。 
     *  
     * 实际底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。 
     */   
    public HashSet() {   
    map = new HashMap<E,Object>();   
    }   
   
    /** 
     * 构造一个包含指定collection中的元素的新set。 
     * 
     * 实际底层使用默认的加载因子0.75和足以包含指定 
     * collection中所有元素的初始容量来创建一个HashMap。 
     * @param c 其中的元素将存放在此set中的collection。 
     */   
    public HashSet(Collection<? extends E> c) {   
    map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));   
    addAll(c);   
    }   
   
    /** 
     * 以指定的initialCapacity和loadFactor构造一个空的HashSet。 
     * 
     * 实际底层以相应的参数构造一个空的HashMap。 
     * @param initialCapacity 初始容量。 
     * @param loadFactor 加载因子。 
     */   
    public HashSet(int initialCapacity, float loadFactor) {   
    map = new HashMap<E,Object>(initialCapacity, loadFactor);   
    }   
   
    /** 
     * 以指定的initialCapacity构造一个空的HashSet。 
     * 
     * 实际底层以相应的参数及加载因子loadFactor为0.75构造一个空的HashMap。 
     * @param initialCapacity 初始容量。 
     */   
    public HashSet(int initialCapacity) {   
    map = new HashMap<E,Object>(initialCapacity);   
    }   
   
    /** 
     * 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。 
     * 此构造函数为包访问权限,不对外公开,实际只是是对LinkedHashSet的支持。 
     * 
     * 实际底层会以指定的参数构造一个空LinkedHashMap实例来实现。 
     * @param initialCapacity 初始容量。 
     * @param loadFactor 加载因子。 
     * @param dummy 标记。 
     */   
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {   
    map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);   
    }   
   
    /** 
     * 返回对此set中元素进行迭代的迭代器。返回元素的顺序并不是特定的。 
     *  
     * 底层实际调用底层HashMap的keySet来返回所有的key。 
     * 可见HashSet中的元素,只是存放在了底层HashMap的key上, 
     * value使用一个static final的Object对象标识。 
     * @return 对此set中元素进行迭代的Iterator。 
     */   
    public Iterator<E> iterator() {   
    return map.keySet().iterator();   
    }   
   
    /** 
     * 返回此set中的元素的数量(set的容量)。 
     * 
     * 底层实际调用HashMap的size()方法返回Entry的数量,就得到该Set中元素的个数。 
     * @return 此set中的元素的数量(set的容量)。 
     */   
    public int size() {   
    return map.size();   
    }   
   
    /** 
     * 如果此set不包含任何元素,则返回true。 
     * 
     * 底层实际调用HashMap的isEmpty()判断该HashSet是否为空。 
     * @return 如果此set不包含任何元素,则返回true。 
     */   
    public boolean isEmpty() {   
    return map.isEmpty();   
    }   
   
    /** 
     * 如果此set包含指定元素,则返回true。 
     * 更确切地讲,当且仅当此set包含一个满足(o==null ? e==null : o.equals(e)) 
     * 的e元素时,返回true。 
     * 
     * 底层实际调用HashMap的containsKey判断是否包含指定key。 
     * @param o 在此set中的存在已得到测试的元素。 
     * @return 如果此set包含指定元素,则返回true。 
     */   
    public boolean contains(Object o) {   
    return map.containsKey(o);   
    }   
   
    /** 
     * 如果此set中尚未包含指定元素,则添加指定元素。 
     * 更确切地讲,如果此 set 没有包含满足(e==null ? e2==null : e.equals(e2)) 
     * 的元素e2,则向此set 添加指定的元素e。 
     * 如果此set已包含该元素,则该调用不更改set并返回false。 
     * 
     * 底层实际将将该元素作为key放入HashMap。 
     * 由于HashMap的put()方法添加key-value对时,当新放入HashMap的Entry中key 
     * 与集合中原有Entry的key相同(hashCode()返回值相等,通过equals比较也返回true), 
     * 新添加的Entry的value会将覆盖原来Entry的value,但key不会有任何改变, 
     * 因此如果向HashSet中添加一个已经存在的元素时,新添加的集合元素将不会被放入HashMap中, 
     * 原来的元素也不会有任何改变,这也就满足了Set中元素不重复的特性。 
     * @param e 将添加到此set中的元素。 
     * @return 如果此set尚未包含指定元素,则返回true。 
     */   
    public boolean add(E e) {   
    return map.put(e, PRESENT)==null;   
    }   
   
    /** 
     * 如果指定元素存在于此set中,则将其移除。 
     * 更确切地讲,如果此set包含一个满足(o==null ? e==null : o.equals(e))的元素e, 
     * 则将其移除。如果此set已包含该元素,则返回true 
     * (或者:如果此set因调用而发生更改,则返回true)。(一旦调用返回,则此set不再包含该元素)。 
     * 
     * 底层实际调用HashMap的remove方法删除指定Entry。 
     * @param o 如果存在于此set中则需要将其移除的对象。 
     * @return 如果set包含指定元素,则返回true。 
     */   
    public boolean remove(Object o) {   
    return map.remove(o)==PRESENT;   
    }   
   
    /** 
     * 从此set中移除所有元素。此调用返回后,该set将为空。 
     * 
     * 底层实际调用HashMap的clear方法清空Entry中所有元素。 
     */   
    public void clear() {   
    map.clear();   
    }   
   
    /**  
     * 返回此HashSet实例的浅表副本:并没有复制这些元素本身。  
     *  
分享到:
评论

相关推荐

    java 运用集的相关类(Set)

    在Java中,Set接口是集合框架的一部分,它代表了不包含重复元素的无序集合。本篇将深入探讨Java中Set接口及其相关的实现类,以及如何在实际编程中运用。 Set接口继承自Collection接口,其主要特性是元素的唯一性,...

    Java集合类原理详解.pdf

    - **集合**:包括List、Set等,其中List保持插入顺序,而Set不允许重复元素。 - **映射**:如HashMap、TreeMap等,通过键值对进行存储和检索。 #### 1.2 Collection `Collection`是Java集合框架的根接口,所有具体...

    java集合类详解(set list ArrayList等java集合类详述)

    Set 是一个不能包含重复元素的集合,SortedSet 是一个按照升序排列元素的 Set。List 是一个有序的集合,可以包含重复的元素,并提供了按索引访问的方式。Map 是一个包含了 key-value 对的集合,SortedMap 是一个按照...

    一眼看懂Java中的集合

    此篇文章是学习Java中的集合时自己总结的笔记,主要记录了集合的底层原理、List、Set、Queue等集合的特点、集合的实现类的特点以及各个实现类底层是原理。

    集合的概念及应用和HashSet保证数据不重复的原理

    今天我们将深入探讨“集合”的概念及其应用,以及HashSet如何保证数据不重复的原理。 首先,集合是一种可以容纳多个对象的容器,这些对象可以是任意类型,只要它们实现了特定接口,如Comparable或Serializable。...

    Java集合排序及java集合类详解(Collection、List、Map、Set).pdf

    Java集合排序及Java集合类...本文详细解释了Java集合框架的实现原理、Collection、List、Set、Map四个接口的定义和实现原理,以及它们的常用方法。同时,本文还对Java集合框架的设计理念和实现原理进行了详细的解释。

    set集合的基本特点,set集合底层去重原理,集合怎么进行排序

    Set集合在Java编程语言中是一种基础且重要的数据结构,它主要特点是存储不重复的元素,且没有特定的插入顺序。接下来我们将深入探讨Set集合的基本特点、底层去重原理以及如何进行排序。 首先,让我们理解Set集合的...

    对Java中Set的深入研究

    本篇文章将详细介绍`Set`接口的实现机制及其内部工作原理,包括如何判断元素是否重复、不同类型的`Set`实现类的特点与应用场景等。 #### 二、Set接口概述 在Java中,`Set`接口定义如下: ```java public ...

    对Java中Set的深入研究.pdf

    总结,Java中的Set接口及其各种实现提供了多种方式来存储和管理不重复的元素。选择合适的Set类取决于具体的需求,如元素的排序、性能、线程安全等因素。理解Set的实现原理和工作方式对于优化代码和避免潜在问题至关...

    Java-Java集合体系-List-Set

    理解并熟练运用Java集合体系中的List、Set、Map接口及其实现类,对于日常开发和面试来说至关重要,因为它们是许多Java框架和库的基础。在实际项目中,根据需求选择合适的集合类型可以提高代码的效率和可维护性。在...

    java集合类原理面试题

    `Set`接口代表无序且不允许元素重复的集合,如`HashSet`和`TreeSet`。`TreeSet`基于红黑树实现,能按照自然顺序或自定义比较器进行排序。`HashSet`则依赖哈希表,插入和查询速度快,但不保证元素顺序。 `List`接口...

    List和Set使用retainAll方法的比较

    - **Set**:Set是无序且不包含重复元素的集合。它不支持索引访问,但提供了一种唯一性保证。常见的Set实现类有HashSet和TreeSet。 2. **retainAll方法的实现原理** - 对于`List`,`retainAll`方法的实现通常是...

    HashSet的实现原理

    在Java编程中,HashSet是一种不允许存储重复元素的集合,它实现了Set接口。HashSet是通过HashMap来实现的,其底层使用HashMap来保存所有元素。这种实现方式让HashSet的操作非常简单高效,因为HashSet的大部分操作,...

    java实现多次HttpURLConnection共享session

    在Java中,HttpURLConnection并不直接支持session管理,所以我们需要手动处理Cookie。以下是一种实现方式: 1. 创建Cookie管理器: 首先,我们需要创建一个`CookieManager`实例,并设置到`java.net.CookieHandler`...

    java 集合框架的原理及其使用

    2. **Set接口**:继承自Collection,不允许重复元素,且通常有自己的排序规则。例如`HashSet`和`TreeSet`。 3. **List接口**:也继承自Collection,允许重复元素,元素保持插入顺序。常用实现有`ArrayList`和`...

    Java集合Collection、List、Set、Map使用详解

    本文将深入解析Java集合中的Collection、List、Set和Map,包括它们的使用方法、实现原理以及如何进行排序。 ### 集合框架概述 1.1.1 容器简介 容器是Java集合框架的基础,它是一个可以存储多个对象的容器,提供了...

    深入Java集合学习系列(三):ArrayList实现原理

    它允许包含重复的元素,也允许插入null值,这是区别于Java集合中的另一个List接口实现类LinkedList的重要特点。ArrayList内部通过一个数组来保存其所有元素,这个数组就是ArrayList的“elementData”字段。 ...

    Java网编程原理与JSP.Web开发核心技术

    考虑到给定的信息,我们将不包含重复的“每日书籍更新收藏必备***”这一部分内容,我们将专注于阐述“Java网编程原理与JSP.Web开发核心技术”这一主题的知识点。 首先,“Java网编程原理”涉及的是一系列基于Java...

Global site tag (gtag.js) - Google Analytics