Set集合
在Collection集合中List集合中的元素有序且允许重复,而Set集合中元素是唯一的,下面为大家介绍几种Set集合。
1、HashSet集合
HashSet集合中元素的存取是无序的,且元素是唯一的。它的底层数据结构是哈希表,具有链表和数组的特点。
HashSet集合靠着重写 hashCode() 和 equals() 方法来实现元素的唯一,如果不重写则不能保证元素的唯一性。
public class SetDemo {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("小明");
set.add("小明");
set.add("小红");
set.add("小红");
set.add("小李");
set.add("小李");
for (String s : set) {
System.out.println(s);
}
}
}
//运行结果为:
小明
小李
小红
由上面的代码可见,当元素重复存储的时候,在输出的时候元素就只有一个,重复的元素没有被存储(因为String类中已经重写过了方法)。如果我们存储的是自定义类的时候需要我们手动重写 hashCode() 和 equals() 方法来保证元素的唯一性。但是在重写的时候我们需要合理的进行重写,尽量减少碰撞。代码实现如下:
Student类
import java.util.Objects;
public class 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 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 &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
Test类
import java.util.HashSet;
public class MyTest {
public static void main(String[] args) {
Student s1 = new Student("王五", 25);
Student s2 = new Student("王五", 25);
Student s3 = new Student("王五", 25);
Student s4 = new Student("王五", 252);
Student s5 = new Student("王五2", 235);
Student s6 = new Student("王五3", 25);
Student s7 = new Student("王五4", 2665);
Student s8 = new Student("王五5", 285);
Student s9 = new Student("王五6", 285);
Student s10 = new Student("王五7", 255);
HashSet<Student> hashSet = new HashSet<>();
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
hashSet.add(s4);
hashSet.add(s5);
hashSet.add(s6);
hashSet.add(s7);
hashSet.add(s8);
hashSet.add(s9);
hashSet.add(s10);
for (Student student : hashSet) {
System.out.println(student.getName() + "==" + student.getAge());
}
}
}
上面的测试类的代码中HashSet集合中存储的为学生类,如果不手动重写 hashCode() 和 equals() 方法那么就无法保证元素的唯一。
2、LinkedHashSet集合
LinkedHashSet集合元素有序并且元素唯一,因为它的底层数据结构是链表和哈希表,链表可以保证元素唯一,哈希表可以保证元素的唯一。
import java.util.LinkedHashSet;
public class MyTest {
public static void main(String[] args) {
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("爱");
linkedHashSet.add("你");
linkedHashSet.add("三");
linkedHashSet.add("千");
linkedHashSet.add("遍");
linkedHashSet.add("三");
linkedHashSet.add("千");
linkedHashSet.add("遍");
linkedHashSet.add("爱");
for (String s : linkedHashSet) {
System.out.println(s);
}
}
}
//运行结果为
爱你三千遍
从运行结果可以看出,遍历的时候输出的顺序和存储的顺序相同,而后面重复的元素也没有重复存储。
3、TreeSet集合
TreeSet集合的特点就是可以对集合进行排序,因为它的底层数据结果为二叉树。排序有两种方法,一种为自然排序,另一种为比较器排序。下面为大家简单来介绍一下这两种排序的方法。
a、自然排序
当存储的元素为基本数据类型的时候,存储的时候就进行排序,当我们遍历的时候已经排好顺序了。举例说明
public class MyTest {
public static void main(String[] args) {
TreeSet<String> treeSet = new TreeSet<>();
TreeSet<Integer> treeSet2 = new TreeSet<>();
treeSet.add("a");
treeSet.add("a");
treeSet.add("b");
treeSet.add("d");
treeSet.add("c");
treeSet2.add(24);
treeSet2.add(19);
treeSet2.add(18);
treeSet2.add(24);
for (String string : treeSet) {
System.out.println(string);
}
System.out.println("------------");
for (Integer integer : treeSet2) {
System.out.println(integer);
}
}
}
运行结果如下图所示
由代码看出,元素在遍历的时候已经排好了顺序。
当我们存储的为自定义类的元素时,我们需要这个自定义类实现 Comparable 接口重写里面的 comPareTo 方法,根据此方法的返回值的正负和0 来决定元素在二叉树的位置。下面让我们定义一个Student类,并对其进行测试。
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 s) {
//比较逻辑是按照年龄大小来排序
int num = this.age - s.age;
//当年龄相同不能说明他是同一个对象,还得比较姓名
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}
}
import java.util.TreeSet;
/**
* @Author: Administrator
* @CreateTime: 2019-05-11 10:31
*/
public class MyTest {
public static void main(String[] args) {
//按照学生的年龄大小来排序
Student s1 = new Student("王五", 21);
Student s11 = new Student("王五", 21);
Student s123 = new Student("李四", 21);
Student s2 = new Student("王五", 22);
Student s3 = new Student("王五111", 25);
Student s4 = new Student("王五123", 252);
Student s5 = new Student("王五2222", 235);
Student s6 = new Student("王五3", 25);
Student s7 = new Student("欧阳王五", 2665);
Student s8 = new Student("琦玉", 288);
Student s9 = new Student("", 285);
Student s10 = new Student("王五7", 255);
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(s1);
treeSet.add(s11);
treeSet.add(s2);
treeSet.add(s3);
treeSet.add(s4);
treeSet.add(s5);
treeSet.add(s6);
treeSet.add(s7);
treeSet.add(s8);
treeSet.add(s9);
treeSet.add(s10);
treeSet.add(s123);
for (Student student : treeSet) {
System.out.println(student);
}
}
}
代码执行结果如下图
由代码执行的结果看,学生已经按照年龄排好了顺序,你想怎样排序就怎样重新compareTo方法中的逻辑。
b、比较器排序
当使用比较器排序的时候,我们需要创建一个类来实现 Comparator 接口,然后重写里面的逻辑,然后再创建该类对象,传入到TreeSet集合中,但是不能每次我们使用比较器排序都要创建一个类,那么我们可以使用匿名对象直接传入,代码实现如下,学生类为上述学生类,测试类如下
import java.util.Comparator;
import java.util.TreeSet;
public class MyTest3 {
public static void main(String[] args) {
//传入一个比较器
Comparator comparator = new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//按照姓名长度来拍
int num = s1.getName().length() - s2.getName().length();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
};
TreeSet<Student> treeSet = new TreeSet<>(comparator);
treeSet.add(new Student("李", 21));
treeSet.add(new Student("李十八", 212));
treeSet.add(new Student("欧阳", 241));
treeSet.add(new Student("王也", 2771));
treeSet.add(new Student("王也也", 21733));
treeSet.add(new Student("王也也", 21733));
treeSet.add(new Student("王也也", 21337));
treeSet.add(new Student("王也也", 217));
treeSet.add(new Student("王也也", 217));
for (Student student : treeSet) {
System.out.println(student);
}
}
}
运行结果如下图
上面的代码是通过传入一个比较器来进行排序的,通过匿名对象传入了一个比较器然后重写compare()方法来确定元素在二叉树中的位置。
上一篇: STL模板库的学习之集合(set)