Set介绍
java.util.Interface Set<E> 接口 extends Collection 接口。
Set接口特点:
- 不允许存储重复的元素。
- 没有索引,所以也不能使用普通for循环进行便利。
(所有实现Set接口的类具有以上特点。)
HashSet集合
此类实现Set接口,由哈希表(实际上是HashMap实例)支持。它不保证集合的迭代顺序; 特别是,它不保证订单会随着时间的推移保持不变。
HashSet特点:
- 不允许存储重复的元素。
- 没有索引,所以也不能使用普通for循环进行便利。
- 是一个无序的集合,存储元素的顺序和取出元素的顺序不一致。
- 此层为一个哈希表(散列表)结构,查询速度非常快。
- 初始数组容量为16。
下面使用代码进行HashSet集合的茶创建:
public static void main(String[] args){
HashSet<Integer> set = new HashSet<>();
//使用add方法进行元素的添加。
set.add(3);
set.add(2);
set.add(2);
set.add(1);
//使用迭代器进行便利()也可以使用增强for循环。
Iterator<Integer> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//输出:
1
2
3
//证明了Hast无序且元素唯一的特点。
HashSet集合存储数据的结构(哈希表)
哈希值
**哈希值:**是一个十进制的整数,由系统随机给出(对象地址值【十六进制】)
在Object中有一个方法,可以获取对象的哈希值。
public static void main(String[] args){
Book bk = new Book();
int i = bk.hashCode();
System.out.println(i);
System.out.println(bk);
}
//输出
288665596
java.awt.print.Book@1134affc
哈希表
JDK1.8之前:哈希表 = 数组 + 链表
JDK1.8之后:
- 哈希表 = 数组 + 链表
- 哈希表 = 数组 + 红黑树(折半查找)
哈希表结构:
存储数据进行到集合中,首先计算元素的哈希值。
判断重复元素的原理
当要add一个新的元素时,add方法会调用hashCode方法,计算字符串的哈希值,在集合中查找是否已经存在了,如果存在则存在哈希冲突,会继续调用equals方法进行字符串比较。如果hashCode和equals都相同则表示存在相同的元素,倒是add失败。
注意:如果HashSet存储的是自定义元素,则必须重写equals和hashCode方法。
Person类没有重写equals和hashCode方法:
public static void main(String[] args) {
HashSet<Person> ps = new HashSet<>();
ps.add(new Person(18, "张三"));
ps.add(new Person(18, "张三"));
Iterator<Person> iterator = ps.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//输出
com.test.www.Person@1134affc
com.test.www.Person@56cbfb61
Person类重写了equals和hashCode方法:
public static void main(String[] args) {
HashSet<Person> ps = new HashSet<>();
ps.add(new Person(18, "张三"));
ps.add(new Person(18, "张三"));
Iterator<Person> iterator = ps.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
//输出
com.test.www.Person@bd8d8
LinkedHashSet
public class LinkedHashSet<E> extends HashSet<E>
继承了HashSet所以已拥有父类所有的方法。
LinkedHashSet特点
只有一条:
在HashSet集合结构基础上多维护了一条链表,用来记录元素的存储顺序。