Java学习-详谈Set集合(HashSet、TreeSet、LinkedHashSet)

1、Set接口

java.util.Set 接口和 java.util.List 接口一样,同样继承自 Collection 接口,它与 Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比 Collection 接口更加严格了。与List接口不同的是, Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复
Java学习-详谈Set集合(HashSet、TreeSet、LinkedHashSet)_第1张图片

1.继承于Collection接口,具有增删查改的方法!
2.AbstractCollection抽象类,实现了Collection接口,并实现了里面的一些方法,如isEmpty、contains等。
3.Set的两个实现类,HashSetTreeSet

  • HashSet实现本质其实就是HashMap,HashSet里面的元素是无序的。
  • TreeSet实现本质其实就是TreeSet,TreeSet里面的元素是有序的。

(Set集合遍历元素的方式可以采用:迭代器,foreach

2、HashSet集合

2.1HashSet介绍

java.util.HashSet 是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序 不一致)。 java.util.HashSet 底层的实现其实是一个 java.util.HashMap 支持.
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性 的方式依赖于hashCodeequals 方法。
HashSet的继承关系

类 HashSet<E>
java.lang.Object
  继承者 java.util.AbstractCollection<E>
      继承者 java.util.AbstractSet<E>
          继承者 java.util.HashSet<E>
类型参数:
E - 此 set 所维护的元素的类型
所有已实现的接口:
Serializable, Cloneable, Iterable<E>, Collection<E>, Set<E>

构造方法:

HashSet() 
构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75HashSet(Collection<? extends E> c) 
构造一个包含指定 collection 中的元素的新 set。
HashSet(int initialCapacity) 
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。
HashSet(int initialCapacity, float loadFactor) 
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。

常用方法:

boolean  add(E e) 
          如果此 set 中尚未包含指定元素,则添加指定元素。
 void   clear() 
          从此 set 中移除所有元素。
 Object clone() 
          返回此 HashSet 实例的浅表副本:并没有复制这些元素本身。
 boolean    contains(Object o) 
          如果此 set 包含指定元素,则返回 trueboolean    isEmpty() 
          如果此 set 不包含任何元素,则返回 true。
 Iterator<E>    iterator() 
          返回对此 set 中元素进行迭代的迭代器。
 boolean    remove(Object o) 
          如果指定元素存在于此 set 中,则将其移除。
 int   size() 
          返回此 set 中的元素的数量(set 的容量)。

2.2HashSet集合存储数据的结构(哈希表)

关于数据结构哈希表详解: 哈希表详解
这里简单介绍一下:
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。 但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度**超过阈值(8)**时,将链表转换为红黑树,这样大大减少了查找 时间。 简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示。
Java学习-详谈Set集合(HashSet、TreeSet、LinkedHashSet)_第2张图片
HashSet存储原理:
Java学习-详谈Set集合(HashSet、TreeSet、LinkedHashSet)_第3张图片
JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一, 其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么 保证其唯一, 就必须复写 hashCodeequals 方法建立属于当前对象的比较方式

2.3HashSet集合特点

import java.util.HashSet;
class test{
     
	public static void main(String []args) {
     
		HashSet<Integer> hs = new HashSet<>();
		hs.add(17);
		hs.add(3);
		hs.add(78);
		hs.add(24);
		hs.add(13);
		System.out.println(hs.add(4));
		System.out.println(hs.add(4));  //检验HashSet是否允许重复元素加入
		System.out.println(hs);    //检验HashSet是否有序	
	}
}
true
false
[17, 3, 4, 24, 13, 78]

第二个输出false说明不允许元素重复,[17, 3, 4, 24, 13, 78]说明存储的元素无序

2.4 HashSet存储自定义类型元素

给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保 证HashSet集合中的对象唯一

import java.util.HashSet;
import java.util.Iterator;
class Student{
     	
	private String name;
	private int id;	
	public Student(){
     }
	public Student(String name, int id)
	{
     
		super();
		this.name = name;
		this.id = id;
	}
	public String getName()
	{
     
		return name;
	}
	public void setName(String name)
	{
     
		this.name = name;
	}
	public int getId()
	{
     
		return id;
	}
	public void setId(int id)
	{
     
		this.id = id;
	}
	@Override
	public String toString()
	{
     
		return "Student [name=" + name + ", id=" + id + "]";
	}	
	@Override
	//重写hashCode方法
	public int hashCode()
	{
     
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	//重写equals方法
	public boolean equals(Object obj)
	{
     
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (id != other.id)
			return false;
		if (name == null)
		{
     
			if (other.name != null)
				return false;
		}
		else if (!name.equals(other.name))
			return false;
		return true;
	}
}
public class test{
     
	public static void main(String []args) {
     
		HashSet<Student> hs = new HashSet<>();	
		hs.add(new Student("张三",1));
		hs.add(new Student("李四",2));
		hs.add(new Student("王五",3));
		hs.add(new Student("张三",1));//因为重写了equals方法和hashCode方法所以实际上集合中只有一个张三1
		System.out.println(hs.add(new Student("谢六",4)));	
		System.out.println(hs.add(new Student("谢六",4)));
		//第一种打印方式,利用重写的toString()方法和Println()直接打印
		System.out.println(hs); 
		System.out.println("------------");
		 //第二种打印方式,foreach增强for循环
		for(Student s : hs) {
       
			System.out.println(s);
		}
		System.out.println("------------");   
		//第三种打印方式,利用Iteator迭代器
		Iterator<Student> it = hs.iterator();
			while(it.hasNext()) {
     
				Student s = it.next();
				System.out.println(s);
			}	
	}
}
true
false
[Student [name=李四, id=2], Student [name=张三, id=1], Student [name=王五, id=3], Student [name=谢六, id=4]]
------------
Student [name=李四, id=2]
Student [name=张三, id=1]
Student [name=王五, id=3]
Student [name=谢六, id=4]
------------
Student [name=李四, id=2]
Student [name=张三, id=1]
Student [name=王五, id=3]
Student [name=谢六, id=4]

2.5HashSet的子类LinkedHashSet

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢? 在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构。
特点:存取有序,唯一,效率高
Java学习-详谈Set集合(HashSet、TreeSet、LinkedHashSet)_第4张图片

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
public class test {
      
	public static void main(String[] args) 
	{
      
		Set<String> set = new LinkedHashSet<String>(); 
		set.add("bbb");
		set.add("aaa"); 
		set.add("Love");
		set.add("abc"); 
		set.add("bbc"); 
		Iterator<String> it = set.iterator(); 
		while (it.hasNext())
		{
      
			System.out.println(it.next()); 
		} 
	} 
}
bbb
aaa
Love
abc
bbc

3、TreeSet集合

3.1TreeSet介绍

基于 TreeMap 的 NavigableSet 实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator进行排序,具体取决于使用的构造方法。
在存储了大量的需要进行快速检索的排序信息的情况下,TreeSet是一个不错的选择
TreeSet继承关系

类 TreeSet<E>
java.lang.Object
  继承者 java.util.AbstractCollection<E>
      继承者 java.util.AbstractSet<E>
          继承者 java.util.TreeSet<E>
类型参数:
E - 此 set 维护的元素的类型
所有已实现的接口:
Serializable, Cloneable, Iterable<E>, Collection<E>, NavigableSet<E>, Set<E>, SortedSet<E>

Java学习-详谈Set集合(HashSet、TreeSet、LinkedHashSet)_第5张图片

继承于AbstractSet,AbstractSet实现了equals和hashcode方法。
实现了NavigableSet接口,意味着它支持一系列的导航方法。比如查找与指定目标最匹配项。
实现了Cloneable接口,意味着它能被克隆。
实现了java.io.Serializable接口,意味着它支持序列化。

构造方法:

TreeSet() 
          构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
TreeSet(Collection<? extends E> c) 
          构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。
TreeSet(Comparator<? super E> comparator) 
          构造一个新的空 TreeSet,它根据指定比较器进行排序。
TreeSet(SortedSet<E> s) 
          构造一个与指定有序 set 具有相同映射关系和相同排序的新 TreeSet

常用方法:

 boolean    add(E e) 
          将指定的元素添加到此 set(如果该元素尚未存在于 set 中)。
 boolean    addAll(Collection<? extends E> c) 
          将指定 collection 中的所有元素添加到此 set 中。
 E  ceiling(E e) 
          返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null。
 void   clear() 
          移除此 set 中的所有元素。
 Object clone() 
          返回 TreeSet 实例的浅表副本。
 Comparator<? super E>  comparator() 
          返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回 null。
 boolean    contains(Object o) 
          如果此 set 包含指定的元素,则返回 true。
 Iterator<E>    descendingIterator() 
          返回在此 set 元素上按降序进行迭代的迭代器。
 NavigableSet<E>    descendingSet() 
          返回此 set 中所包含元素的逆序视图。
 E  first() 
          返回此 set 中当前第一个(最低)元素。
 E  floor(E e) 
          返回此 set 中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null。
 SortedSet<E>   headSet(E toElement) 
          返回此 set 的部分视图,其元素严格小于 toElement。
 NavigableSet<E>    headSet(E toElement, boolean inclusive) 
          返回此 set 的部分视图,其元素小于(或等于,如果 inclusive 为 true)toElement。
 E  higher(E e) 
          返回此 set 中严格大于给定元素的最小元素;如果不存在这样的元素,则返回 null。
 boolean    isEmpty() 
          如果此 set 不包含任何元素,则返回 true。
 Iterator<E>    iterator() 
          返回在此 set 中的元素上按升序进行迭代的迭代器。
 E  last() 
          返回此 set 中当前最后一个(最高)元素。
 E  lower(E e) 
          返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null。
 E  pollFirst() 
          获取并移除第一个(最低)元素;如果此 set 为空,则返回 null。
 E  pollLast() 
          获取并移除最后一个(最高)元素;如果此 set 为空,则返回 null。
 boolean    remove(Object o) 
          将指定的元素从 set 中移除(如果该元素存在于此 set 中)。
 int    size() 
          返回 set 中的元素数(set 的容量)。
 NavigableSet<E>    subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) 
          返回此 set 的部分视图,其元素范围从 fromElement 到 toElement。
 SortedSet<E>   subSet(E fromElement, E toElement) 
          返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
 SortedSet<E>   tailSet(E fromElement) 
          返回此 set 的部分视图,其元素大于等于 fromElement。
 NavigableSet<E>    tailSet(E fromElement, boolean inclusive) 
          返回此 set 的部分视图,其元素大于(或等于,如果 inclusive 为 true)fromElement。

3.2TreeSet特点

import java.util.Set;
import java.util.TreeSet;

class Test{
     
	public static void main(String []args) {
     
		Set<Integer> st = new TreeSet<>();
		st.add(1);
		st.add(4);
		st.add(5);
		st.add(2);
		System.out.println(st.add(2)); //验证是否可以添加重复元素
		System.out.println(st);		
	}
}
false
[1, 2, 4, 5]
  • false说明TreeSet集合不允许重复
  • [1, 2, 4, 5]说明,TreeSet对Integer数据类型进行升序排列
import java.util.Set;
import java.util.TreeSet;
class test{
     
	public static void main(String []args) {
     
		Set<String> st = new TreeSet<>();
		st.add("张三");
		st.add("李四");
		st.add("王五");
		st.add("谢六");
		st.add("d");
		st.add("a");
		st.add("c");
		st.add("b");
		System.out.println(st.add("王五"));
		System.out.println(st);		
	}
}
false
[a, b, c, d, 张三, 李四, 王五, 谢六]

Java在String和Integer类里重写了comparaTo方法,因此TreeSet可以对其进行升序排列。当我们对自定义的TreeSet进行排序时,就需要自己重写比较方法。如果说没有重写任何比较器(内部或者外部)时,使用TreeSet进行操作会报错

3.3TreeSet与比较器

TreeSet与内部比较器

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
class Student implements Comparable{
     	
	 String name;
	 int age; 
	public Student(){
     }
	public Student(String name, int age)
	{
     
		super();
		this.name = name;
		this.age = age;
	}
	@Override
	//内部重写比较器
	public int compareTo(Object o)
	{
     
		Student stu =((Student)o);
		return this.age-stu.age;  //按照年龄升序排序
	}
	@Override
	public String toString()
	{
     
		return "Student [name=" + name + ", age=" + age + "]";
	}
}
class test{
     
	public static void main(String []args) {
     
		Set<Student> st = new TreeSet<>();
		st.add(new Student("张三",18));
		st.add(new Student("李四",19));
		st.add(new Student("王五",20));
		st.add(new Student("谢六",10));
		Iterator<Student> it = st.iterator(); 
		while (it.hasNext())
		{
      
			System.out.println(it.next()); 
		} 		
	}
}
Student [name=谢六, age=10]
Student [name=张三, age=18]
Student [name=李四, age=19]
Student [name=王五, age=20]

TreeSet与外部比较器

import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
class Student{
     	
	 String name;
	 int age; 
	public Student(){
     }
	public Student(String name, int age)
	{
     
		super();
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString()
	{
     
		return "Student [name=" + name + ", age=" + age + "]";
	}
}
//外部比较器
class OutsideCompare implements Comparator{
     
	@Override
	public int compare(Object o1, Object o2)
	{
     
		Student st1 = ((Student) o1);
		Student st2 = ((Student) o2);
		return st1.age-st2.age;
	}
}
public class test{
     
	public static void main(String []args)
	{
     
		OutsideCompare com = new OutsideCompare();
		Set<Student> st = new TreeSet<>(com);//根据指定的比较器定义的构造方法
		st.add(new Student("张三",18));
		st.add(new Student("李四",19));
		st.add(new Student("王五",20));
		st.add(new Student("谢六",10));
		Iterator<Student> it = st.iterator(); 
		while (it.hasNext())
		{
      
			System.out.println(it.next()); 
		} 		
	}
}

欢迎持续关注!
个人博客站:jQueryZk Blog

你可能感兴趣的:(java学习,java,Set集合,HashSet,TreeSet,LinkedHashSet)