Set继承于Collection接口,是一个不允许出现重复元素,并且无序的集合,主要有HashSet和TreeSet两大实现类。

在判断重复元素的时候,Set集合会调用hashCode()和equal()方法来实现。

HashSet是哈希表结构,主要利用HashMap的key来存储元素,计算插入元素的hashCode来获取元素在集合中的位置;

TreeSet是红黑树结构,每一个元素都是树中的一个节点,插入的元素都会进行排序;

Set集合框架结构:

java redis 地理位置 java redis hset_属性值

 

1.1 Set常用方法

与List接口一样,Set接口也提供了集合操作的基本方法。

但与List不同的是,Set还提供了equals(Object o)和hashCode(),供其子类重写,以实现对集合中插入重复元素的处理;

public interface Set<E> extends Collection<E> {

   // 添加功能
    boolean add(E e);
    boolean addAll(Collection<? extends E> c);

   // 删除功能
    boolean remove(Object o);
    boolean removeAll(Collection<?> c);
    void clear();

    //长度功能
    int size();

    //判断功能
    boolean isEmpty();
    boolean contains(Object o);
    boolean containsAll(Collection<?> c);
    boolean retainAll(Collection<?> c); 

    //获取Set集合的迭代器:
    Iterator<E> iterator();

    //把集合转换成数组
    Object[] toArray();
    <T> T[] toArray(T[] a);
    
    //判断元素是否重复,为子类提高重写方法
    boolean equals(Object o);
    int hashCode();
}

HashSet实现Set接口,底层由HashMap(后面讲解)来实现,为哈希表结构,新增元素相当于HashMap的key,value默认为一个固定的Object。

有元素插入的时候,会计算元素的hashCode值,将元素插入到哈希表对应的位置中来;

它继承于AbstractSet,实现了Set, Cloneable, Serializable接口。

(1)HashSet继承AbstractSet类,获得了Set接口大部分的实现,减少了实现此接口所需的工作,实际上是又继承了AbstractCollection类;

(2)HashSet实现了Set接口,获取Set接口的方法,可以自定义具体实现,也可以继承AbstractSet类中的实现;

(3)HashSet实现Cloneable,得到了clone()方法,可以实现克隆功能;

(4)HashSet实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。

具有如下特点:

  • 不允许出现重复因素;
  • 允许插入Null值;
  • 元素无序(添加顺序和遍历顺序不一致);
  • 线程不安全,若2个线程同时操作HashSet,必须通过代码实现同步;

1.3 HashSet基本操作

HashSet底层由HashMap实现,插入的元素被当做是HashMap的key,根据hashCode值来确定集合中的位置,由于Set集合中并没有角标的概念,所以并没有像List一样提供get()方法。当获取HashSet中某个元素时,只能通过遍历集合的方式进行equals()比较来实现;

import java.util.Objects;

public class Student_Set {
	private String name;
	private int age;
	public Student_Set() {
		
	}
	public Student_Set(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;
	}
	@Override
	public boolean equals(Object o) {
		if(this==o) return true;
		if(o==null || getClass()!=o.getClass())  return false;
		Student_Set student=(Student_Set) o;
		return age==student.age && Objects.equals(name, student.name);
		
	}
	@Override
	public int hashCode() {
		return Objects.hash(name,age);
	}
	public String toString() {
		return "Student{name="+name+",age="+age+"}";
	}

}
public class A01_HashSetDemo1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		/*
		 哈希值:
		 对象的整数表现形式:
		 1.如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
		 2.如果已经重写hashCode方法,不同对象只要属性值相同,计算出的哈希值就是一样的
		 3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
		 */
		
		//1.创建对象
		Student s1=new Student("张三",23);
		Student s2=new Student("张三",23);
		
		//2.如果已经重写hashCode方法,不同对象只要属性值相同,计算出的哈希值就是一样的
	    //3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
		
		//在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
		System.out.println("abc".hashCode());//96354
		System.out.println("abc".hashCode());//96354

	}

}