与Collection相比较,Set接口并没有扩充对Collection接口进行功能上的扩充,而且所有Set集合底层都是依靠Map实现。Set和Map密切相关。Map的遍历需要先变成单列集合,只能变成Set集合。
一、HashSet集合
1.HashSet是Set接口的实现类
2.特点:元素唯一、元素无序、无索引、线程不安全
3.数据结构:哈希表
a. jdk8之前:哈希表=数组+链表
b.jdk8之后:哈希表=数组+链表+红黑树。
加入红黑树的目的:加快查询速度
4.方法:和 Collection一样
5.遍历:(1)增强for; (2)迭代器
public class Demo01HashSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("cat0");
set.add("dog0");
set.add("cat1");
set.add("dog1");
set.add("cat2");
set.add("dog0");
System.out.println(set);
//输出:[cat2, cat0, cat1, dog1, dog0]
System.out.println("===================");
//迭代器
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("===================");
//增强for
for (String s : set) {
System.out.println(s);
}
}
二、LinkedHashSet
1.LinkedHashSet 继承了HashSet。
2.特点:元素唯一、元素有序、无索引、线程不安全
3.数据结构:哈希表+双向链表
4.使用:和HashSet一样
三、哈希值
哈希值是由计算机算出来的一个十进制数,可以看作是对象的地址值。获取对象的哈希值,使用的是Object中的方法:public native int hashCode() 。
public static void main(String[] args) {
Person p1 = new Person("xiaotao", 18);
Person p2 = new Person("wangfang", 20);
System.out.println(p1);
System.out.println(p2);
/*
输出:March.MyHash.Person@1e643faf
March.MyHash.Person@6e8dacdf
*/
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
/*
输出:509886383
1854778591
*/
System.out.println(Integer.toHexString(509886383));
System.out.println(Integer.toHexString(1854778591));
/*
输出:1e643faf
6e8dacdf
*/
}
String的hashCode是由符号串的内容决定的。 but字符串不一样不代表Hash值一定不一样。
System.out.println("=============");
String s1="abc";
String s2=new String("abc");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
/*
输出:96354
96354
*/
System.out.println("=============");
String s3="通话";
String s4="重地";
System.out.println(s3.hashCode());
System.out.println(s4.hashCode());
/*
输出:1179395
1179395
*/
在类中重写hashCode(),则回根据类的属性生成hashCode,两个对象如果属性都相同,那么hashCode也相同。【如果重写了HashCode方法,那么计算的就是对象内容的哈希值】
@Override public int hashCode() { return Objects.hash(name,age); }
哈希值不一样,内容肯定不一样;哈希值一样,内容也可能不一样(存在哈希冲突)。
HashSet的存储去重复的过程
1.先 计算元素的哈希值(重写hashCode方法),在比较内容(重写equals方法)
2.先比较哈希值,如果哈希值不一样,存储
3.如果哈希值一样,再比较内容
a. 如果哈希值一样,内容不一样,存储
b. 如果哈希值一样,内容也一样,去重复
如果不重写HashCode和equals方法,默认调用的是Object中的,那么不容的对象,肯定哈希值不一样并且也不相等。【默认的hashCode类似对象地址,具有唯一性;默认的equals也是通过比较两个对象的地址来判断是否相等】