set集合的概述
- set集合的特点
- 集合中的对象不按特定方式排序
- 没有重复对象,元素唯一
- set集合的实现类
- Set主要有两个实现类:HashSet和TreeSet。
- HashSet类按照哈希算法来存取集合中的对象,当向集合中加入这个对象时,HahshSet会调用对象的hashCode()方法来获得哈希码,然后根据哈希码进一步计算出对象在集合中存放的位置,因此存取速度比较快。HashSet类还有一个子类LinkedHashSet类,它不仅实现了哈希算法,而且还实现了链表数据结构。链表数据结构能够提高插入和删除元素的性能。
- TreeSet类实现了SortSet接口,具有排序功能。
HashSet类
HashSet按照Hash算法存储集合中的元素,具有很好的存取和查找性能。当向HashSet中添加一些元素时,HashSet会根据该对象的HashCode()方法来得到该对象的HashCode值,然后根据这些HashCode的值来决定元素的位置。
- HashSet的特点:
- 存储顺序和添加的顺序不同
- HashSet不是同步的,如果多个线程同时访问一个HashSet,假设有两个或更多的线程修改了集合中的值,则必须通过代码使线程同步。 - HastSet允许集合中的元素为null。
- JDK1.7 HashSet的数据结构是 数组跟链表
- JDK1.8 HashSet的数据结构是 数组跟链表和二叉树
- 判断两个元素相同的标准是:
两个对象通过equals()方法相等,且HashCode()方法的返回值也相等。如果元素不重写这两个方法则无法保证元素的唯一性
LinkedHashSet类
LikedHashSet是HashSet的子类,它也是根据元素的HashCode值进来决定元素的存储位置,但它能够同时使用链表来维护元素的添加次序,使得元素能以插入顺序保存。
public class LinkHashSetTest {
public static void main(String[] args){
LinkedHashSet lh = new LinkedHashSet();
lh.add(1);
lh.add(2);
lh.add(3);
//输出:[1, 2, 3]
System.out.println(lh);
lh.remove(1);
lh.add(1);
//输出:[ 2, 3 ,1]
System.out.println(lh);
}
}
TreeSet类
- TreeSet 集合的特点:
- 元素唯一,且能对元素进行排序
- TreeSet 底层的数据结构是二叉树
- TreeSet 对元素进行排序
- 排序会分为两种:1,自然排序,2,比较器排序
- 采用空参构造时,就用的是自然排序,自然排序要求元素必须实现一个Compareble 接口 并且重写接口中 compareTo 这个比较的方法,根据此方法的返回值的正负0 来决定元素放置到树结构的位置,以及不往里面放
- 下面举例说明自定义学生类通过学生姓名长度或是年龄进行排序
测试类:
public class MyTest {
public static void main(String[] args) {
TreeSet<Student> set = new TreeSet<>();
set.add(new Student("赵六", 26));
set.add(new Student("赵六2", 26));
set.add(new Student("张三2222", 233));
set.add(new Student("田七", 230));
set.add(new Student("吴八222", 2313));
set.add(new Student("张三22", 23));
set.add(new Student("张三222", 23));
set.add(new Student("李四11111111", 24));
set.add(new Student("王五", 20));
//按照学生的年龄大小进行排序
//按照名字的长度来排序
// System.out.println(set);
for (Student student : set) {
System.out.println(student);
}
}
}
学生类重写comparable方法通过年龄进行排序:
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student student) {
//System.out.println("会调用比较方法");
//如果年龄一样,还得比较姓名
int num = this.age - student.age;
//if(num==0){
// num=this.name.compareTo(student.name);
//}
int num2 = num == 0 ? this.name.compareTo(student.name) : num;
return num2;
}
}
学生类通过重写comparable方法,比较学生姓名长度进行排序
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student student) {
//比较逻辑,
//按照姓名的长度来排序
int num = this.name.length() - student.name.length();
//当姓名长度一样时,还得比较姓名的内容
int num2 = num == 0 ? this.name.compareTo(student.name) : num;
//当姓名的长度和内容一样时,害得比较姓名是否一样
int num3 = num2 == 0 ? this.age - student.age : num2;
return num3;
}
}