Java集合系列之HashSet源碼分析

來源:互聯網
上載者:User

標籤:

一、HashSet簡介

  HashSet是Set介面典型實現,它按照Hash演算法來儲存集合中的元素,具有很好的存取和尋找效能。主要具有以下特點:

  • 不保證set的迭代順序
  • HashSet不是同步的,如果多個線程同時訪問一個HashSet,要通過代碼來保證其同步
  • 集合元素值可以是null

  當向HashSet集合中存入一個元素時,HashSet會調用該對象的hashCode()方法來得到該對象的hashCode值,然後根據該值確定對象在HashSet中的儲存位置。在Hash集合中,不能同時存放兩個相等的元素,而判斷兩個元素相等的標準是兩個對象通過equals方法比較相等並且兩個對象的HashCode方法傳回值也相等。

  下面的例子說明了上述特性:

public class Person{    String name;    int age;        public Person(String name,int age)    {        this.name=name;        this.age=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;    }    //當對象的名字和姓名相同即返回true    public boolean equals(Object obj)    {        if(obj==null)            return false;        if((this.name.equals(((Person)obj).name) && this.age==((Person)obj).age))                return true;        else            return false;    }    }

  此時添加兩個name和age均相同的Person對象執行個體到HashSet中:

public class HashSetDemo{    public static void main(String[] args)    {        HashSet<Person> hs = new HashSet<>();                Person p1=new Person("xujian", 23);        Person p2=new Person("xujian", 23);        hs.add(p1);        hs.add(p2);        for(Person p:hs)        {            System.out.println(p.name+"---"+p.age);        }    }}

  

  可見,HashSet中存放了兩個name和age均相同的Person對象。

  接下來我們重寫一下Person類的hashCode方法,使其返回相同的HashCode。

public class Person{    String name;    int age;        public Person(String name,int age)    {        this.name=name;        this.age=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 int hashCode()    {        // TODO 自動產生的方法存根        return 1;    }    //當對象的名字和姓名相同即返回true    public boolean equals(Object obj)    {        if(obj==null)            return false;        if((this.name.equals(((Person)obj).name) && this.age== ((Person)obj).age))                return true;        else            return false;    }    }

  再次執行向HashSet添加元素操作,會發現此時HashSet只儲存了一個。

  

  HashSet中每一能儲存元素的槽位通常稱為“桶”,如果有多個元素的hashCode相同,但是通過equals方法比較返回false,就需要在一個桶上存放多個元素。

二、HashSet源碼分析  1、建構函式

  HashSet的底層實際上是由HashMap實現的。其四個建構函式分別對應相應的HashMap。

  //構造一個新的,空的HashSet,其底層 HashMap執行個體的預設初始容量是 16,載入因子是 0.75    public HashSet()     {        map = new HashMap<>();    }    //構造一個包含指定 collection 中的元素的新 set    public HashSet(Collection<? extends E> c)     {        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));        addAll(c);    }   //構造一個新的空 set,其底層 HashMap 執行個體具有指定的初始容量和指定的載入因子    public HashSet(int initialCapacity, float loadFactor) {        map = new HashMap<>(initialCapacity, loadFactor);    }    //構造一個新的空 set,其底層 HashMap 執行個體具有指定的初始容量和預設的載入因子0.75    public HashSet(int initialCapacity)    {        map = new HashMap<>(initialCapacity);    }
  2、HashSet常用方法

  boolean add(E e): 如果此 set 中尚未包含指定元素,則添加指定元素

public boolean add(E e)     {        //調用map的put方法,其中value值為靜態Object對象        return map.put(e, PRESENT)==null;    }

  void clear():從此 set 中移除所有元素

 public void clear()     {        map.clear();    }

  Object clone():返回此 HashSet 執行個體的淺表副本

 public Object clone()    {        try         {            //調用父類的clone方法            HashSet<E> newSet = (HashSet<E>) super.clone();            newSet.map = (HashMap<E, Object>) map.clone();            return newSet;        }         catch (CloneNotSupportedException e)        {            throw new InternalError(e);        }    }

  boolean contains(Object o):如果此 set 包含指定元素,則返回 true

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

  boolean isEmpty():如果此 set 不包含任何元素,則返回 true

public boolean isEmpty()     {        return map.isEmpty();    }

  Iterator<E> iterator():返回對此 set 中元素進行迭代的迭代器

 public Iterator<E> iterator()    {        return map.keySet().iterator();    }

  boolean remove(Object o):如果指定元素存在於此 set 中,則將其移除

 public boolean remove(Object o)     {        return map.remove(o)==PRESENT;    }

  int size():返回此 set 中的元素的數量

    public int size()     {        return map.size();    }
三、HashSet的應用範例程式碼
public class HashSetDemo{    public static void main(String[] args)    {        HashSet<String> hs1 = new HashSet<>();   //無參建構函式建立一個預設大小為16,裝載因子為0.75的HashSet        System.out.println("調用add函數");        hs1.add("Hello");        hs1.add("World");        hs1.add("nihao");                HashSet<String> hs2 = new HashSet<>(hs1); //構造一個包含hs1中元素的HashSet                System.out.println("調用remove函數");        hs1.remove("Hello");        for(String str:hs1)            System.out.println(str);            System.out.println("調用clone函數");        HashSet<String> hs3=(HashSet<String>) hs2.clone();        for(String str:hs3)            System.out.println(str);                System.out.println("利用迭代器遍曆HashSet中元素");        Iterator<String> it=hs2.iterator();        while(it.hasNext())        {            System.out.println(it.next());        }                System.out.println("調用size函數");                System.out.print(hs2.size());    }}

  執行結果

Java集合系列之HashSet源碼分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.