Set接口下的HashSet、LinkedHashSet、TreeSet分析

Set接口下的HashSet、LinkedHashSet、TreeSet分析

Set接口框架

Set接口:存储无序、不可重复的数据
HashSet:主要实现类,线程不安全,可以存储null值。
LinkedHashSet:是HashSet的子类,遍历内部的数据时,可以按照添加的顺序遍历。
TreeSet:可以按照添加的对象指定属性,进行排序。

如何理解Set的无序和不可重复

  • 无序性
    不等于随机性,每次顺序实际上是相同的,但是不是按照存储顺序存放。
    存储的数据在底层数组中并非按照数组索引的顺序做的添加,而是根据数据的哈希值决定的。
  • 不可重复性
    保证添加的元素按照equals()方法判断时不能返回true,即:相同的元素只能添加一个。
    Set接口下的HashSet、LinkedHashSet、TreeSet分析_第1张图片

添加元素的过程:以hashSet为例说明

向hashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a 的哈希值,此哈希值接着通过某种算法计算出HashSet底层数组中的存在位置(即:索引位置),判断数组此位置上是否已经有元素。
如果此位置上没有其他元素,则元素a添加成功。
如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值,
如果hash值不相同,则元素a添加成功,
如果hash值相同,进而需要调用元素a所在类的equals()方法
如果equals()返回true,元素a添加失败,
如果equals()返回false,则元素a添加成功。

对于添加成功的情况2和情况3而言:元素a与已经存在指定索引位置上的数据就以链表的方式存储,(在jdk7中元素a放入数组中,指向原来的元素,而在jdk8中原来的元素在数组中指向元素a)“7上8下”

hashSet的底层实际上是数组加链表的结构。

要求向Set当中添加的数据,其所在的类一定要重写hashCode()和equals()方法,重写的hashCode()和equals()方法尽量要保持一致性。相等的对象要具有相同的散列值
(也就是equals是true的时候,hash值也一定要一样,equals返回为true 的时候,hash值不要一样。)

LinkedHashSet

存放顺序和遍历的顺序相同,但是仍然是无序集合(存储不是按照顺序存储)ListedHashSet是hashSet的子类,在添加数据的同时还维护了两个引用,记录此数据前一个数据和后一个数据,目的:(优点)对于频繁的遍历操作,LiskedHashSet的效率要高于hashSet。(因为能够很快的找到后一个元素)

Set接口下的HashSet、LinkedHashSet、TreeSet分析_第2张图片

TreeSet

可以根据对象的指定属性进行排序。
要求向TreeSet中添加的数据要求是同一个类的。
Integer、String是按照从小到大顺序排序…
自定义对象的顺序需要告诉TreeSet怎么排序,(使用自然排序或者定制排序)

@data
public class User{
     
	private String name;
	private Integer age;
}
//按照姓名从小到大排列
@Override
public int compareTo(object o){
     
	if(o instanceof User){
     
		User user = (User)o;
		return this.name.compareTo(user.name);
	}else{
     
		throw new RuntimeException("输入的类型不匹配");
	}
}

TreeSet set = new TreeSet();
set.add(new User("Tom", 12));
set.add(new User("Jerry", 32));
set.add(new User("Jim", 2));
set.add(new User("Mike", 65));
set.add(new User("Jack", 33));

Iterator iterator = set.inerator();
while(iterator.hasNext()){
     
	System.out.println(iterator.next());
}

Set接口下的HashSet、LinkedHashSet、TreeSet分析_第3张图片
上面的写法由于只对姓名进行比较会导致相同姓名但是年龄不同的对象只能在集合中存储一个,所以需要优化一个比较的写法。

//按照姓名从大到小,年龄从小到大排列。
@Override
public int compareTo(object o){
     
	if(o instanceof User){
     
		User user = (User)o;
		int compare = -this.name.compareTo(user.name);
		if(compare != 0){
     
			return compare;
		}else{
     
			return Integer.compare(this.age, user.age);
		}
	}else{
     
		throw new RuntimeException("输入的类型不匹配");
	}
}

自然排序中,比较两个对象是否相同的标准为:compareTo()返回0,不是equals()。
Set接口下的HashSet、LinkedHashSet、TreeSet分析_第4张图片
TreeSet和TreeMap都是红黑树的内存结构。不能容忍相同的元素。

你可能感兴趣的:(java,java)