Set集合:无序(存储顺序和取出顺序不一致),唯一。
Set子类:HashSet、LinkedHashSet、TreeSet。
一、HashSet
HashSet:不保证Set的迭代顺序,特别是它不保证该顺序永恒不变。
底层数据结构是哈希表(元素的链表的数组)。
哈希表依赖于哈希值存储。
添加功能底层依赖两个方法:
(1). int hashCode()
(2).boolean equals(Object obj)
首先比较哈希值,如果相同,则比较地址值是否相同或者equals。
代码示例1:
//测试Set集合无序,唯一
Set<String> set = new HashSet<String>();
set.add("hello world");
set.add("java");
set.add("您好");
set.add("hello world");
set.add("java");
for (String s:set) {
System.out.println(s);
}
打印结果:
java
您好
hello world
示例代码2:
public class GenericTest {
public static void main(String[] args) {
HashSet<Student> set = new HashSet<Student>();
Student student1 = new Student("张三",18);
Student student2 = new Student("李四",19);
Student student3 = new Student("王五",20);
Student student4 = new Student("张三",21);
Student student5 = new Student("李四",19);
set.add(student1);
set.add(student2);
set.add(student3);
set.add(student4);
set.add(student5);
for (Student student : set){
System.out.println("姓名:"+student.getName()+" 年龄:"+student.getAge());
}
}
}
class Student{
private String name;
private int age;
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;
}
}
打印结果:
姓名:李四 年龄:19
姓名:张三 年龄:18
姓名:王五 年龄:20
姓名:李四 年龄:19
姓名:张三 年龄:21
结果出现重复数据:原因是因为HashSet底层依赖的是hashCode()方法和equals方法。
而这两个方法在Student中没有重写,所以默认使用的是Object类。
实例化Student对象的哈希值不同,所以出现重复数据。
重写hashCode()方法和equals方法代码示例:
public class GenericTest {
public static void main(String[] args) {
//测试Set集合无序,唯一
HashSet<Student> set = new HashSet<Student>();
Student student1 = new Student("张三",18);
Student student2 = new Student("李四",19);
Student student3 = new Student("王五",20);
Student student4 = new Student("张三",21);
Student student5 = new Student("李四",19);
set.add(student1);
set.add(student2);
set.add(student3);
set.add(student4);
set.add(student5);
for (Student student : set){
System.out.println("姓名:"+student.getName()+" 年龄:"+student.getAge());
}
}
}
class Student{
private String name;
private int age;
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 int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
if (this == obj){
return true;
}
if (!(obj instanceof Student)){
return false;
}
Student s = (Student)obj;
return this.name.equals(s.name) && this.age == s.age;
}
}
打印结果为:
姓名:张三 年龄:18
姓名:李四 年龄:19
姓名:王五 年龄:20
姓名:张三 年龄:21
二、LinkedHashSet
LinkedHashSet 底层数据结构由哈希表和链表组成。
哈希表保证元素的唯一性。
链表保证元素有序(存储和取出一致)。
代码示例:
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
linkedHashSet.add("hello world");
linkedHashSet.add("java");
linkedHashSet.add("您好");
linkedHashSet.add("hello world");
linkedHashSet.add("java");
linkedHashSet.add("您好");
for (String s : linkedHashSet){
System.out.println(s);
}
打印结果:
hello world
java
您好
三、TreeSet
1.自然排序:使用元素的自然顺序对元素进行排序。自然排序需要类实现Comparable接口,重写Compareto方法 。
2.比较器排序: 实现Comparator接口,并重写compare(T o1, T o2)方法:
TreeSet底层数据结构是红黑树(红黑树是一种自平横的二叉树)。
代码示例1:自然排序
TreeSet<Integer> treeSet = new TreeSet<Integer>();
treeSet.add(20);
treeSet.add(19);
treeSet.add(18);
treeSet.add(24);
treeSet.add(9);
treeSet.add(27);
treeSet.add(26);
treeSet.add(20);
treeSet.add(7);
treeSet.add(50);
treeSet.add(1);
for (Integer integer : treeSet){
System.out.println(integer);
}
打印结果:
1
7
9
18
19
20
24
26
27
50
按自然排序并且去掉重复数据:自然排序和唯一性。
代码示例2:自然排序
public class GenericTest {
public static void main(String[] args) {
//TreeSet存储自定义对象并保证排序和唯一性,自然排序。
TreeSet<Student> treeSet = new TreeSet<Student>();
treeSet.add(new Student("zhangsan",21));
treeSet.add(new Student("lisi",25));
treeSet.add(new Student("wangwu",24));
treeSet.add(new Student("zhangsan",27));
treeSet.add(new Student("yangtong",31));
treeSet.add(new Student("lisi",25));
treeSet.add(new Student("jiabaoyu",20));
treeSet.add(new Student("lindaiyu",19));
for (Student student : treeSet){
System.out.println("姓名:"+student.getName()+" 年龄:"+student.getAge());
}
}
}
class Student implements Comparable<Student>{
private String name;
private int age;
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 int compareTo(Student o) {
//按年龄进行排序
int num = this.age - o.age;
int num2 = num == 0 ? this.name.compareTo(o.name) : num;
return num2;
}
}
打印结果:
姓名:lindaiyu 年龄:19
姓名:jiabaoyu 年龄:20
姓名:zhangsan 年龄:21
姓名:wangwu 年龄:24
姓名:lisi 年龄:25
姓名:zhangsan 年龄:27
姓名:yangtong 年龄:31
代码示例3:定义比较器排序
public class GenericTest {
public static void main(String[] args) {
//
TreeSet<Student> treeSet = new TreeSet<Student>(new MyComparetor());
treeSet.add(new Student("zhangsan",21));
treeSet.add(new Student("lisi",25));
treeSet.add(new Student("wangwu",24));
treeSet.add(new Student("zhangsan",27));
treeSet.add(new Student("yangtong",31));
treeSet.add(new Student("lisi",25));
treeSet.add(new Student("jiabaoyu",20));
treeSet.add(new Student("lindaiyu",19));
for (Student student : treeSet){
System.out.println("姓名:"+student.getName()+" 年龄:"+student.getAge());
}
}
}
class Student{
private String name;
private int age;
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 int compareTo(Student o) {
//按年龄进行排序
int num = this.age - o.age;
int num2 = num == 0 ? this.name.compareTo(o.name) : num;
return num2;
}*/
}
class MyComparetor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
//按年龄进行排序
int num = o1.getAge() - o2.getAge();
int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;
return num2;
}
}
打印结果:
姓名:lindaiyu 年龄:19
姓名:jiabaoyu 年龄:20
姓名:zhangsan 年龄:21
姓名:wangwu 年龄:24
姓名:lisi 年龄:25
姓名:zhangsan 年龄:27
姓名:yangtong 年龄:31