Set概述
Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
Set集合的特点
-
元素存取无序
-
没有索引、只能通过迭代器或增强for循环遍历
-
不能存储重复元素
-
String两次new相同的内容是可以添加进set集合中的,因为指向的内存地址是一样的,而其他对象是不能的
HashCode
-
哈希值简介
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
-
如何获取哈希值
Object类中的public int hashCode():返回对象的哈希码值
-
哈希值的特点
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
HashSet集合
它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于: hashCode() 与 equals ()方法。
方法 | 说明 |
---|---|
add((Object obj) | 向Set集合中添加元素,添加成功返回true,否则返回false |
remove(Object obj) | 删除Set集合中的元素,删除成功返回true,否则返回false。 |
contains(Object o) | 如果Set包含指定的元素,则返回 true,否则返回false |
clear() | 移除此Set中的所有元素 |
size() | 返回Set集合中的元素个数 |
isEmpty() | 如果Set不包含元素,则返回 true ,否则返回false |
iterator() | 返回在此Set中的元素上进行迭代的迭代器 |
HashSet集合的特点
-
底层数据结构是哈希表
-
对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
-
没有带索引的方法,所以不能使用普通for循环遍历
-
由于是Set集合,所以是不包含重复元素的集合
HashSet集合保证元素唯一性源码分析
-
HashSet集合保证元素唯一性的原理
1.根据对象的哈希值计算存储位置
如果当前位置没有元素则直接存入
如果当前位置有元素存在,则进入第二步
2.当前元素的元素和已经存在的元素比较哈希值
如果哈希值不同,则将当前元素进行存储
如果哈希值相同,则进入第三步
3.通过equals()方法比较两个元素的内容
如果内容不相同,则将当前元素进行存储
如果内容相同,则不存储当前元素
-
HashSet集合保证元素唯一性的图解
package Day0817am;
import java.util.HashSet;
import java.util.Iterator;
import org.junit.Test;
public class demo1 {
@Test
public void test1(){
//将四个城市保存到Set集合中
//创建并实例化一个HashSet集合容器
/*HashSet集合容器的特点:
* 1.元素无序
* 2.元素唯一,不存在相同的元素
* 3.底层是基于Hash算法,所以元素没有索引,只能通过迭代器或增强for循环遍历
*/
HashSet<String> c = new HashSet<String>();
//add方法向集合容器中添加元素
c.add("上海1");
c.add("上海2");
c.add("上海3");
c.add("上海4");
//遍历 增强for OR 迭代器
System.out.println("增强for循环");
for(String s : c){
System.out.println(s);
}
System.out.println("迭代器");
//获取HashSet集合对象中的迭代器
Iterator<String> it = c.iterator();
while(it.hasNext()){//hasNext()判断是否还存在元素
System.out.println(it.next());//next()获取元素
}
System.out.println("通过迭代器删除上海2");
Iterator<String> itr = c.iterator();
while(itr.hasNext()){//hasNext()判断是否还存在元素
String s = itr.next();//next()获取元素
if("上海2".equals(s)){
itr.remove();
}
}
System.out.println("删除过后,增强for循环");
for(String s : c){
System.out.println(s);
}
}
}
哈希表
哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示。
LinkedHashSet
HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序
HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构。
LinkedHashSet集合特点
- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
- 由哈希表保证元素唯一,也就是说没有重复的元素
TreeSet
TreeSet集合特点
- 元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法
- TreeSet():根据其元素的自然排序进行排序
- TreeSet(Comparator comparator) :根据指定的比较器进行排序
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以不包含重复元素的集合