Set
- 特点:无序,唯一(不重复)
HashSet
- 采用Hashtable哈希表存储结构
- 优点:添加速度快、查询速度快、删除速度快
- 缺点:无序
LinkedHashSet
- 采用哈希表存储结构,同时使用链表维护次序
- 有序(添加顺序)
TreeSet
-
采用二叉树(红黑树)的存储结构
-
优点:有序,查询速度比List快
-
缺点:查询速度没有HashSet快
-
代码示例
package com.bjsxt.set1;
import java.util.HashSet;
import java.util.Iterator;
/**
* HashSet:无序,唯一
* LinkedHashSet: 有序(添加顺序), 唯一
* TreeSet:红黑树(二叉树、二叉查找树、二叉平衡树)有序(自然顺序),唯一
* <p>
* Set是无序的,相比Collection没有增加任何方法,List相比Collection增加和索引相关的方法
*/
public class TestSet1 {
public static void main(String[] args) {
// 创建Set集合对象
HashSet<String> set = new HashSet<>();
// 添加元素
set.add("JavaSE");
set.add("MySQL");
set.add("JavaSE");
set.add("Web");
set.add("JavaEE");
System.out.println(set.size());
System.out.println(set);
System.out.println("------遍历方法1:for-each------");
for (String s : set) {
System.out.println(s);
}
System.out.println("------遍历方法2:Iterator------");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("------遍历方法3:lambda表达式+stream流------");
set.forEach(System.out::println);
}
}
运行结果
- 自定义Student类
未重写hashCode和equals方法
package com.bjsxt.set1;
public class Student {
private String name;
private String sex;
private int age;
private double score;
public Student() {
}
public Student(String name, String sex, int age, double score) {
this.name = name;
this.sex = sex;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
存储多个学生信息
package com.bjsxt.set1;
import java.util.HashSet;
import java.util.Set;
public class TestSet2 {
public static void main(String[] args) {
Set<Student> set = new HashSet<>();
// 使用set存储多个学生信息
Student student1 = new Student("zhangsan1", "男", 23, 98);
Student student2 = new Student("zhangsan2", "女", 22, 99);
Student student3 = new Student("zhangsan3", "女", 24, 97);
Student student4 = new Student("zhangsan1", "男", 23, 98);
set.add(student1);
set.add(student2);
set.add(student3);
set.add(student4);
System.out.println(set.size()); // 结果为4
for (Student stu: set) {
System.out.println(stu);
}
}
}
运行结果
【解决方法】:重写Student类的equals和hashCode方法
package com.bjsxt.set1;
import java.util.Objects;
public class Student {
private String name;
private String sex;
private int age;
private double score;
public Student() {
}
public Student(String name, String sex, int age, double score) {
this.name = name;
this.sex = sex;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", score=" + score +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Double.compare(student.score, score) == 0 && Objects.equals(name, student.name) && Objects.equals(sex, student.sex);
}
@Override
public int hashCode() {
return Objects.hash(name, sex, age, score);
}
}
运行结果
问题1:为什么HashSet、LinkedHashSet存储String是唯一的,但是存储Student不唯一了?
解决:重写Student类的equals()和hashCode(),缺一不可
问题2:为什么TreeSet存储String是有序的,但是存储Student却报异常:java.lang.ClassCastException:Student cannot be cast to Comparable
解决:重写compareTo
哈希表
-
hashtable也叫散列表,特点:快
-
结构:结构有多种。最流行、最容易理解:顺序表+链表
-
主结构:顺序表,每个顺序表的节点再单独引出一个链表
-
添加数据的过程
- 计算哈希码x(调用hashCode(),结果是一个int值,整数的哈希码取自身即可)
- 计算在哈希表中的存储位置:y = k(x) = x%数组长度(如上图数组为0~12共13个位置,则计算存储位置公式为:y=x%13)
- 存入哈希表:
- 情况一:一次添加成功
- 情况二:多次添加成功(出现了冲突,调用equals()和对应链表的元素进行比较,比较到最后,结果都是false,创建新节点,存储数据,并加入链表末尾)
- 情况三:不添加(出现了冲突,调用equals()和对应链表的元素进行比较,经过一次或者多次比较后,结果是true,表明重复,不添加)
-
小结论:
- 哈希表添加数据快(3步即可,不考虑冲突)
- 唯一,无序