22_Object 类和 Set 集合
1、Object 类
1.1 Object 类概述
Java 中所有类的基类,Java 中任何一个类都是 Object 类的子类或者间接子类。Object 类内提供的方法所有类都可以使用。
目前需要了解的三类方法:
1、比较相关
boolean equals(Object obj);
判断参数对象和调用方法的对象是否为同一个对象
int hashCode();
获取当前对象的哈希值
2、线程相关
wait();
wait(int ms);
notify();
notifyAll();
3、数据字符串描述相关
String toString();
提供当前对象的字符串信息描述
1.2 重写 equals()
流程
1、判断参数对象和调用方法的对象是否为同一个对象(指向同一个地址),若是同一个对象,返回true;
2、若不是同一个对象,继续判断当前参数对象和调用方法的对象是否是同一个数据类型,若不是同一个类型,返回false;
3、若是同一个类型,继续判断参数对象和调用方法的对象的数据内容是否完全相同,若完全相同返回true,否则返回false。
public boolean equals(Object obj) {
//1、判断调用方法的对象和参数对象是否为同一个即【同地址】对象
if (this == obj) {
return true;
}
/*
* 2、判断调用方法的对象和参数对象是否为同一个类型
*
* instanceof 关键字 判断当前对象类型是否为当前类型
*/
if (!(obj instanceof Student)) {
return false;
}
//3、进行对象数据内容判断
//3.1 强制类型转换
Student stu = (Student)obj;
/*
* 3.2 比较方法调用的对象和参数对象的内容是否一致
*
* int id ==
* String name 字符串判断方法 equals()
* int age ==
*/
return id == stu.id
&& name.equals(stu.name)
&& age == stu.age;
}
1.3 重写 hashCode()
Java 中要求:如果两个对象使用 equals() 判断结果为 true,证明两个对象实际上是同一个对象,那么两个对象调用 hashCode()
得到的哈希值必须一致。
hashCode() 在没有重写的情况下,默认返回值数据是当前对象在内存中的存储数据的地址内容(十进制表示),该数据具备唯一
性,可以作为身份标识。
/*
* 证明两个对象为同一个对象
* 规定通过 hashCode() 得到的哈希值必须一致
*/
@Override
public int hashCode() {
/*
* Object 的工具类 Objects 中的方法 hash(Object...values)
*
* Object...
* 不定长参数 需要提供的数据类型必须是 Object 类型 等价于 Java中任意的数据类型都支持
* 方法体中是 Object[]
*
* hash(Object...values)
* 根据内容返回哈希值
*/
return Objects.hash(id, name, age);
}
2、Set 集合
2.1 Set 集合概述
Set 集合的方法都来自于 Collection 集合 没有特征方法
Set 集合特征:
1、无序
2、不可重复
Set 集合接口的两个实现类
1、class HashSet
底层结构为 哈希表结构,要求添加数据必须有比较方式,保证数据唯一性
2、class TreeSet
底层结构为 二叉树结构,要求添加数据必须有自然顺序或者比较顺序的方式
import java.util.HashSet;
/*
* Set 集合特征演示
* 1、存储元素无序
* 2、存储元素不可重复
*/
public class Demo1 {
public static void main(String[] args) {
/*
* Set 是一个接口
* 没有实例化对象 需要使用 Set 集合的实现类 HashSet 类的实例化对象
*
* 1、无序
* 数据添加顺序和数据存储顺序不一致
* 2、不可重复
*
*/
HashSet<String> set = new HashSet<String>();
set.add("aaa");
set.add("bbb");
//添加失败返回 false
boolean ret = set.add("bbb");
set.add("ccc");
set.add("ddd");
set.add("eee");
set.add("fff");
set.add("ggg");
System.out.println(ret);
System.out.println(set);
}
}
2.2 HashSet 实现类
底层结构为 哈希表结构,添加元素时需要提供哈希值,所以进行添加元素操作会调用 hashCode()
import java.util.HashSet;
public class Demo2 {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<Person>();
/*
* 每调用一次添加元素方法 调用一次 hashCode 方法
*/
set.add(new Person(1, "甲", 18));
set.add(new Person(2, "乙", 18));
set.add(new Person(3, "丙", 18));
set.add(new Person(4, "丁", 18));
System.out.println();
/*
* 执行添加操作
* 要添加的元素按照重写 equals 方法和 hashCode 方法判断是否和集合中已经存在的元素相同
*
* 每执行一次添加操作 都会调用 hashCode 方法
* 得到该元素对应的哈希值 即添加的元素在集合中对应应该存储位置
* 如果发现该位置已经存在元素
* 调用 equals 方法进行比较 返回值为 true 时表示两个元素相同 无法添加
* 返回值为 false 可以添加 避免出现 哈希值相同但 equals 方法返回值不同的情况
*/
boolean ret = set.add(new Person(4, "丁", 18));
System.out.println(ret);
System.out.println("size: " + set.size());
}
}
2.3 TreeSet 实现类
TreeSet 实现类底层结构为二叉树结构
树状结构要求添加元素必须进行大小比较,即被添加的元素必须有自然顺序或者可比较的方式
2.4 TreeSet 存储自定义元素的方案
【方案一】
自定义类实现 Comparable 接口,变成可比较的类型
/*
* 实现接口 Comparable 接口泛型约束为 SingleDog 类型
* 实现接口中的 int CompareTo(SingleDog o) 方法
*
* 可比较的类型
*/
public class SingleDog implements Comparable<SingleDog> {
private int id;
private String name;
private int age;
public SingleDog() {}
public SingleDog(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 "SingleDog [id=" + id + ", name=" + name + ", age=" + age + "]";
}
/*
* 实现 Comparable接口的 compareTo 方法 返回值类型为 int 类型
*
* 返回值可以分为两种情况
* 1、负数或者正数 两个元素存在大小关系 不确定升序还是降序
* 2、0 证明两个元素一致 按照Set 集合特征 无法存储相同元素
*/
@Override
public int compareTo(SingleDog o) {
//按照年龄进行比较操作
return age - o.age;
}
}
import java.util.TreeSet;
public class Demo4 {
public static void main(String[] args) {
/*
* 实例化 TreeSet对象约束具体数据类型为 自定义类型后
* 可以进行排序的方式一:
* 自定义类型实现 Comparable<T> 接口 重写接口中的 compareTo 方法
*/
TreeSet<SingleDog> set = new TreeSet<SingleDog>();
/*
* TreeSet 结构存储的SingleDog 类型 实现了接口 Comparable
* 是一个可比较的类型 TreeSet 允许存储
*
* TreeSet 接口会自动执行 SingleDog 类实现的 Comparable 接口中的 compareTo 方法
* 从而满足当前存储结构排序特征
*/
set.add(new SingleDog(1, "甲", 18));
set.add(new SingleDog(2, "乙", 17));
set.add(new SingleDog(3, "丙", 16));
set.add(new SingleDog(4, "丁", 20));
System.out.println(set);
}
}
【方案二】
TreeSet 插件式增强,提供比较排序存储元素的比较器,比较器实现 Comparator 接口
import java.util.Comparator;
import java.util.TreeSet;
/*
* 使用 Comparator 接口实现类对象增强 TreeSet
*
* 自定义比较器实现 Comparator 接口 实现接口中的 compare 方法
* int compare(T o1, T o2);
*/
class PersonComparator implements Comparator<Person> {
/*
* 实现 Comparator 接口的 compare 方法 返回值类型为 int 类型
*
* 返回值可以分为两种情况
* 1、负数或者正数 两个元素存在大小关系 不确定升序还是降序
* 2、0 证明两个元素一致 按照 Set 集合特征 无法存储相同元素
*/
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
}
public class Demo5 {
public static void main(String[] args) {
/*
* 通过构造方法参数提供自定义 PersonComparator 类的实例化对象
*
* Comparator 接口实现类中的 compare 方法由 TreeSet结构自行调整
*/
TreeSet<Person> set = new TreeSet<Person>(new PersonComparator());
/*
* TreeSet 结构存储的Person 类型 实现了接口 Comparable
* 是一个可比较的类型 TreeSet 允许存储
*
* TreeSet 接口会自动执行 PersonComparator 比较器实现 Comparator 接口中的 compare 方法
* 从而满足当前存储结构排序特征
*/
set.add(new Person(1, "甲", 18));
set.add(new Person(2, "乙", 17));
set.add(new Person(3, "丙", 16));
set.add(new Person(4, "丁", 20));
}
}