无序:添加数据的顺序和获取出的数据顺序不一致;不重复;不索引。
注意:Set常用到的方法,基本上就是Collection提供的,自己几乎没有额外新增一些常用功能。
(1)哈希值:就是一个int类型的随机值,java中每个对象都有一个哈希值。java中的所有对象,都可以调用Object类提供的hashCode方法,返回该对象的哈希值。
格式:
public int hashCode():
(2)对象哈希值的特点:
(3)哈希表:
(4)过程:(jDK8之前)
红黑树:就是可以自平衡的二叉树,红黑树是一种增删改查数据性能相对较好的结构。
package com.item.demo1hashset;
import java.util.*;
public class SetDemo1 {
public static void main(String[] args) {
Set<String> set =new HashSet<>();//一行经典的代码
set.add("java");
set.add("java");
set.add("鸿蒙");
set.add("鸿蒙");
set.add("电商设计");
set.add("电商设计");
set.add("新媒体");
set.add("大数据");
System.out.println(set);//[java, 新媒体, 鸿蒙, 电商设计, 大数据]
System.out.println("============");
Set<String> set1 =new LinkedHashSet<>();
set1.add("java");
set1.add("java");
set1.add("鸿蒙");
set1.add("鸿蒙");
set1.add("电商设计");
set1.add("电商设计");
set1.add("新媒体");
set1.add("大数据");
System.out.println(set1);//[java, 鸿蒙, 电商设计, 新媒体, 大数据]
System.out.println("============");
Set<Double> set2 =new TreeSet<>();//一行经典的代码
set2.add(5.1);
set2.add(5.1);
set2.add(1.0);
set2.add(2.0);
set2.add(1.0);
set2.add(3.0);
set2.add(2.0);
set2.add(5.4);
System.out.println(set2);//[1.0, 2.0, 3.0, 5.1, 5.4]
System.out.println("=============");
String s1="acd";
String s2="abc";
System.out.println(s1.hashCode());//96386
System.out.println(s1.hashCode());//96386
System.out.println(s2.hashCode());//96354
System.out.println(s2.hashCode());//96354
}
}
需求:
创建一个存储学生对象的集合,存储多个学生对象,要求:多个学生对象的成员变量值相同时,我们就认为是同一个对象,要求只保留一个。
分析:
1.定义学生类,创建HashSet集合对象,创建学生对象。
2.把学生添加到集合。
结论:如果希望Set集合认为2个内容一样的对象是重复的,必须重写对象的hashCode()和equals()方法
主类代码:
package com.item.demo1hashset;
import java.util.*;
public class SetDemo2 {
public static void main(String[] args) {
Student s1 = new Student("小王", 18, "北京", "123456");
Student s2 = new Student("小李", 19, "北京", "987654");
Student s3 = new Student("小王", 18, "北京", "123456");
Student s4 = new Student("小李", 189, "北京", "987654");
Set<Student> set = new HashSet<Student>();
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
System.out.println(set);
//在没有写equals和hashcode方法时,没有去重!!!,因为这些在java里面每次创建一个新的对象,则地址不一样,存入也不一样。
}
}
Student类代码:
package com.item.demo1hashset;
import java.util.Objects;
public class Student {
private String name;
private int age;
private String address;
private String phone;
public Student() {
}
public Student(String name, int age, String address, String phone) {
this.name = name;
this.age = age;
this.address = address;
this.phone = phone;
}
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
//这里写入equals和hashCode方法
@Override
public boolean equals(Object o) {
//1.如果自己和自己比返回true
if (this == o) return true;
//2.如果o为空或者o不是Student类型返回false
if (o == null || getClass() != o.getClass()) return false;
//3.将o转换成Student类型
Student student = (Student) o;
//4.比较属性是否相同
return age == student.age && Objects.equals(name, student.name) && Objects.equals(address, student.address) && Objects.equals(phone, student.phone);
}
@Override
public int hashCode() {
return Objects.hash(name, age, address, phone);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}'+"\n";
}
}
依然是基于哈希表(数组、链表、红黑树)实现的。
但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
基于红黑树实现的排序
注意:
1.对于数值类型:Integer,Double,默认按照数值本身的大小进行升序排序
2.对于字符串类型,默认按照首字符的编号升序排序
3.对于自定义类型如Student对象,TreeSet默认是无法直接排序的。
解决方法:
1.对象类实现一个Comparable比较接口,重写compare方法,指定大小比较规则。
2.public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则。
主类代码:
package com.item.demo1hashset;
import java.util.*;
public class SetDemo3 {
public static void main(String[] args)
{
Set<Teacher> teachers1=new TreeSet<>();
teachers1.add(new Teacher("小王", 18,3245.2));
teachers1.add(new Teacher("小李", 19,3345.3));
teachers1.add(new Teacher("小孙", 20,3609.4));
teachers1.add(new Teacher("小张", 18,2780.3));
System.out.println(teachers1);//不修改就无法去重
//解决方法2:
Set<Teacher> teachers=new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
return Double.compare(o2.getSalary(), o1.getSalary());//降序
}
});
//继续简化
//Set teachers=new TreeSet<>((o1, o2)->Double.compare(o2.getSalary(), o1.getSalary()));
teachers.add(new Teacher("小王", 18,3245.2));
teachers.add(new Teacher("小李", 19,3345.3));
teachers.add(new Teacher("小孙", 20,3609.4));
teachers.add(new Teacher("小张", 18,2780.3));
System.out.println(teachers);
//解决方法
//1,对象类实现一个Comparable比较接口,重写compare方法,指定大小比较规则。
//2.public TreeSet(Comparator c)集合自带比较器Comparator对象,指定比较规则。
//解决方法2:
Set<Teacher> teachers2=new TreeSet<>();
teachers2.add(new Teacher("小王", 18,3245.2));
teachers2.add(new Teacher("小李", 19,3345.3));
teachers2.add(new Teacher("小孙", 20,3609.4));
teachers2.add(new Teacher("小张", 18,2780.3));
System.out.println(teachers);
}
}
Teacher类代码:
package com.item.demo1hashset;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher implements Comparable<Teacher>{
private String name;
private int age;
private double salary;
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}'+"\n";
}
//解决方法1:重写方法,比较两个对象的大小
@Override
public int compareTo(Teacher o) {
//按照年龄升序
return this.getAge()-o.getAge();
}
}