哈希值(哈希码值)?
是JDK根据对象地址, 或者属性值, 计算出来的int类型的值
Object类中有一个方法可以获取对象的哈希值
public int hashCode(); 根据对象地址计算哈希值并返回
对象哈希值的特点?
1. 如果我们没有重写hashCode(), 那么根据对象的"地址值"计算哈希值
同一个对象多次调用hashCode()获取的哈希值是一样的, 因为地址一样
不同对象的哈希值是不一样的, 因为地址不一样
2. 如果我们重写了hashCode(), 那么根据对象的"属性值"计算哈希值
和对象地址就无关了!
可能出现不同地址的对象, 但是哈希值一样, 原因是属性可能会一样
代码示例
//测试类
public class Demo {
public static void main(String[] args) {
//创建对象
Student s1 = new Student("张三", 18);
Student s2 = new Student("李四", 28);
//打印s1哈希值
System.out.println(s1.hashCode()); //根据地址2129789493 / 根据属性24021577
System.out.println(s1.hashCode()); //根据地址2129789493 / 根据属性24021577
//打印s2哈希值
System.out.println(s2.hashCode()); //根据地址668386784 / 根据属性26103919
//创建s3和s1属性相同,但是地址不同,打印s3哈希值
Student s3 = new Student("张三", 18);
System.out.println(s3.hashCode()); //根据属性24021577
}
}
//学生类
class Student {
@Override
public int hashCode() {
/*
注意: 如果我们重写了hashCode(), 那么根据对象的"属性值"计算哈希值
和对象地址就无关了!
*/
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
...
}
11. HashSet
需求: 创建HashSet集合存储学生对象并遍历, 如果学生对象的成员变量相同, 认为是同一个对象不存
重点: 重写Student类的hashCode和equals方法即可
需求: 创建HashSet集合存储学生对象并遍历, 如果学生对象的成员变量相同, 认为是同一个对象不存
重点: 重写Student类的hashCode和equals方法即可
代码示例
public class Demo {
public static void main(String[] args) {
//创建集合添加元素
HashSet<Student> set = new HashSet<>();
Student s1 = new Student("张飞",18);
Student s2 = new Student("张飞",18);
Student s3 = new Student("吕布",20);
set.add(s1);
set.add(s2);
set.add(s3);
//遍历集合
for (Student stu : set) {
System.out.println(stu);
/*
打印结果
Student{name='张飞', age=18}
Student{name='张飞', age=18}
Student{name='吕布', age=20}
还是出现重复对象的原因
当前Student没有重写HashCode方法, 比较的是对象的地址值
s1和s2两个对象地址不同,所以计算出来的哈希值也不同!
重写Student类的hashCode和equals方法即可
重写后
Student{name='吕布', age=20}
Student{name='张飞', age=18}
结论
如果HashSet集合要存储自定义类的对象,那么该类必须重写hashCode和equals方法
*/
}
}
}
class Student{
// 重写Student类的hashCode和equals方法即可
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
...
}
12. HashSet-小结
Set接口: 无序,无索引,不能重复
HashSet实现类: 底层哈希表,如果存储自定义类,该类要重写hashCode和equals方法
TreeSet实现类: 底层红黑树,可以排序,默认使用自然排序,也可以指定规则使用比较器排序