Set接口中的HashSet与LinkedHashSet

时间:2021-01-22 17:56:54
     Set接口也是Collection接口下的一个子接口,它主要包含以下三个实现类: 1:HashSet 2:LinkedHashSet 3:Treeset      其中,HashSet是Set接口中的主要实现类,下面具体介绍一下Set 1:Set类和List类相反,它所存入的元素的顺序是无序性的并且是不可重复的,也就是说事先存入的时候我们并不能够知道被存入元素将会被放在哪个位置,并且如果尝试存入多个相同的元素,只有第一个能被存进去。      Set类中的方法是和其父类Collection使用的方法是相同的,具体使用方法请看我的另一篇文章:容器 ;       下面来看Set主要实现类Hasnset的具体例子 import java.util.HashSet; import java.util.Set; import org.junit.Test; public class TestSet {         @Test         public void TestHashSet1 (){               Woman P1 = new Woman("美女" ,20);               Woman P2 = new Woman("美女" ,20);                Set A = new HashSet();                A.add(123);                A.add("帅哥" );                A.add("小孩" );                A .add("小孩");                A.add(P1);                A.add(P2);               System. out.println(A .size());               System. out.println(A );        } } class Woman{         private String name ;         private int age ;         public Woman() {                super();        }         public Woman(String name , int age) {                super();                this.name = name ;                this.age = age ;        }         @Override        public String toString() {               return "Woman [name=" + name + ", age=" + age + "]" ;       } }//输出结果如下 //5 //[小孩, 123, 帅哥, Woman [name=美女, age=20], Woman [name=美女, age=20]]
     通过上面的例子,我们可以看到存入其中的对象的顺序确实是无序的,但是我们发现了一个问题,就是在存入一个对象Woman时,存入两个相同的对象P1与P2居然存了进去,而存入两个 "小孩" 确没有存进去,这是有原因的: 2:由于Set中的元素存入时会使用哈希算法从而达到无序存入元素的目的,当我们在Set中添加对象时,会先调用此对象所在类的hashCode()方法,产生一个哈希值,这个哈希值决定了此对象在Set中被存入的位置,如果在此位置上没有对象存储,则存入这个对象,若已有对象存入,则继续调用equals()方法去比较两个对象是否完全相同,如果相同,则后一个对象时不能够被添加进来的,那么也有以下这几种情况:      ①两个对象的哈希值相同,但是所含的内容不同      ②两个对象所含的内容相同,但是算出来的哈希值却是不同的 出现上面情况的原因主要是hashCode()方法中的哈希算法出了问题,也就是说你的哈希算法不够严谨,通常我们要求在添加进Set中的元素所在的类是必须要重写equals()方法和hashCode()方法的,就像上面那个例子一样,由于Woman类中没有重写这两个方法,所以它调用的equals()和hashCode()方法都是Object类中的(会比较他们的地址想不相同,显然P1与P2的地址是不同的),自然就导致相同的对象都被存了进去,具体的重写方法如下:         @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 (getClass() != obj .getClass())                      return false ;              Woman other = (Woman) 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 ;       }     所以在今后的开发过程中,在使用到Set类的时候,一定要重写将存入其中的对象所属类中的equals()方法和hashCode()方法。********************************************************************************************************************************************************下面来看一个有意思的事情,利用LinkedHashSet实现类去实现Set:import java.util.HashSet;import java.util.Iterator;import java.util.LinkedHashSet;import java.util.Set;import org.junit.Test;                     @Test        public void TestLinkedHashSet1 (){               Set A = new LinkedHashSet();               A.add(123);               A.add("帅哥" );               A.add("小孩" );               A.add("MM" );               Iterator iterator = A.iterator();               while(iterator .hasNext())              {                     System. out.println(iterator .next());              }       }输出结果如下:123帅哥小孩MM     细心的朋友可能发现了,这个通过迭代器遍历LinkedHashSet类输出的顺序怎么是按照添加的顺序来的呢,Set类不是说是无序的吗?这里就要说说它的另一个实现类LinkedHashSet了,他使用链表纪录了添加进集合中的顺序,导致我们遍历LinkedHashSet集合的元素时是按照添加的顺序输出的,请看图:
Set接口中的HashSet与LinkedHashSet
从上图我们可以看到当元素计算完哈希值存入时,指针会按顺序指向下一个插入的结点从而导致了遍历时是按照插入顺序遍历的     所以,从上面的例子可以显然看出,LiknedHashSet的插入速度要比HashSet慢,但是在迭代访问Set集合中的所有元素时,LinkedHashSet的速度是要优于HashSet的