Java HashSet

Set集合,先从HashSet学起。

1.HashSet底层实际上是一个HashMap,HashMap底层采用了哈希表数据结构。

2.哈希表又叫做散列表,哈希表底层是一个数组,这个数组中每一个元素是一个单向链表,每一个单向链表都有一个独一无二的hash值,代表数组的下标。在某个单向链表中的每一节点上的hash值是相等的,hash值实际上是key调用hashCode方法,再通过“hash function”转换成的值。

3.如何向哈希表中添加元素:

先调用被存储的key的hashCode方法,经过某个算法得出hash值,如果在这个哈希表中不存在这个hash值,则直接加入元素。如果该hash值已经存在,继续调用key之间的equals方法,如果equals方法返回false,则将该元素添加,如果equals方法返回true,则放弃添加该元素。

4.HashSet其实是HashMap中的key部分,HashSet有什么特点,HashMap中的key应该有相同的特点。

5.HashMap和HashSet的初试化容量都是16,默认加载因子是0.75.

结合下面这个程序来看。

import java.util.*;
public class HashSetTest01{
 public static void main(String[] args){
   //创建Set集合
   Set s=new HashSet();
   //添加元素
   s.add(1);
   s.add(1);
   
   s.add(23);
   s.add(3);
   s.add(10);
   
   Iterator it=s.iterator();
   while(it.hasNext()){
     System.out.println(it.next());
   }
 }
}

编译运行后输出:

1
3
23
10

上述代码中,首先创建一个Set集合s,然后用add()方法向其中添加元素,之后使用迭代器对其进行迭代并且输出其中的元素。从编译运行输出的结果我们可以看出,Set集合是无序并且不可重复的。

接下来看看看关于往Set集合中存储的元素,该元素的hashCode和equals方法。结合以下代码来看:

import java.util.*;
public class HashSetTest02{
 public static void main(String[] args){
   //创建Set集合
   Set es=new HashSet();
   //创建Employee类型的对象
   Employee e1=new Employee("1000","JACK");
   Employee e2=new Employee("1000","JACK");
   Employee e3=new Employee("2000","JSDD");
   Employee e4=new Employee("2001","CJS");
   Employee e5=new Employee("3000","sdc");
   Employee e6=new Employee("3001","mdwkm");
   //Set集合中添加元素
   es.add(e1);
   es.add(e2);
   es.add(e3);
   es.add(e4);
   es.add(e5);
   es.add(e6);
   //输出Set集合元素的个数
   System.out.println(es.size());
   //查看e1,e2的hashCode()方法
   System.out.println(e1.hashCode());
   System.out.println(e2.hashCode());
 }
}
//根据现实的业务逻辑得知,该公司的员工编号是:1000-9999
class Employee{
 String no;
 String name;
 Employee(String no,String name){
   this.no=no;
   this.name=name;
 }
}

编译运行后输出:

6
366712642
1829164700

上述代码中:

1.首先创建一个Set集合es,接着创建六个Employee类型的对象,e1和e2的工号和名字相同,从编译运行后的结果可以看出,e1和e2都被添加到Set集合当中去了,在现实中出于实际需要的考虑,e2不应该被添加进去,因此必须重写Object中的hashCode()方法(Object中的方法一般都是让我们根据现实业务的需要重写的)。

2.重写hashCode()方法有固定的技巧,在上面代码实例中,以员工编号分组重写hashCode()方法,使其散列均匀分布。

public int hashCode(){
 return no.hashCode();
}

3.当hashCode方法返回的值不同时,可以直接往集合中添加元素。当hashCode方法返回的值相同时,需要调用equals()方法,这里需要我们重写equals()方法。

public boolean equals(Object o){
   if(this==o){
     return true;
   }
   if(o instanceof Employee){
     Employee e=(Employee)o;
     if(e.no.equals(this.no) && e.name.equals(this.name)){
       return true;
     }
   }
   return false;
 }

整个的代码如下所示:

import java.util.*;
public class HashSetTest02{
 public static void main(String[] args){
   //创建Set集合
   Set es=new HashSet();
   //创建Employee类型的对象
   Employee e1=new Employee("1000","JACK");
   Employee e2=new Employee("1000","JACK");
   Employee e3=new Employee("2000","JSDD");
   Employee e4=new Employee("2001","CJS");
   Employee e5=new Employee("3000","sdc");
   Employee e6=new Employee("3001","mdwkm");
   //Set集合中添加元素
   es.add(e1);
   es.add(e2);
   es.add(e3);
   es.add(e4);
   es.add(e5);
   es.add(e6);
   //输出Set集合元素的个数
   System.out.println(es.size());
   //查看e1,e2的hashCode()方法
   System.out.println(e1.hashCode());
   System.out.println(e2.hashCode());
 }
}
class Employee{
 String no;
 String name;
 Employee(String no,String name){
   this.no=no;
   this.name=name;
 }
 //重写equals方法
 //如果员工编号相同,并且名字相同,则是同一个对象
 public boolean equals(Object o){
   if(this==o){
     return true;
   }
   if(o instanceof Employee){
     Employee e=(Employee)o;
     if(e.no.equals(this.no) && e.name.equals(this.name)){
       return true;
     }
   }
   return false;
 }
 
 //重写hashCode方法
 public int hashCode(){
   return no.hashCode();
 }
}

重写hashCode和equals方法之后,编译运行输出:

5
1507423
1507423

从上面的结果可以看出,当出现相同的员工编号和姓名时,只会添加进去一个对象,实现了现实业务的需求。

原文地址:https://www.cnblogs.com/naihuangbao/p/9444489.html