equal和hashcode
equal和hashcode
核心代码示例
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
{
return false;
}
Brand brand = (Brand) o;
return Objects.equals(name, brand.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
hashCode() 方法
- hashCode() 的作用是为对象生成一个数字“指纹”(哈希码),这个“指纹”主要用于提高在基于哈希的集合(如 HashSet、HashMap)中的查找速度.
哈希码
哈希码是一个 int 类型的整数。理想情况下,相等的对象应该拥有相同的哈希码。不相等的对象,它们的哈希码最好也不同(但这不是强制要求,只是为了让性能更好)。
哈希码原理
- 计算哈希码: 当你要添加一个新对象(比如 new Brand("BMW"))时,HashSet 首先调用这个对象的 hashCode() 方法,得到一个数字,比如 123。
- 定位“桶”: HashSet 内部其实是一个数组,它用这个哈希码(123)通过一个算法计算出这个对象应该存放在数组的哪个位置(这个位置被称为“桶”或“bucket”)。
快速判断: - 比较: 如果这个“桶”是空的,说明这个对象肯定不存在,直接放进去。整个过程连一次 equals() 调用都不需要;如果这个“桶”里已经有对象了(这种情况叫“哈希冲突”),这时才需要启动 equals() 方法,让新对象和桶里的那几个对象逐一比较,看是否真的相等。
equals()与hashcode()的联系
- Java 规定,这两个方法必须遵守一个非常重要的契约:
如果两个对象通过 equals() 方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode() 方法都必须产生相同的整数结果。
反过来则不成立:如果两个对象的 hashCode() 相同,它们不一定 equals()(这就是哈希冲突)。
所以在修改判断标准时,equals和hashcode要共同重写。
图形展示
graph TD
subgraph "HashSet 内部结构 (一个哈希表)"
direction LR
subgraph "内部数组 (桶数组 Bucket Array)"
direction TB
B0["桶 0<br>Index: 0"]
B1["桶 1<br>Index: 1"]
B2["桶 2<br>Index: 2"]
B3["桶 3<br>Index: 3"]
B4["桶 4<br>Index: 4"]
B5["桶 5<br>Index: 5"]
B6["桶 6<br>Index: 6"]
Bn["..."]
end
subgraph "桶 2 中的内容 (哈希冲突)"
direction TB
Node1["对象: new Brand('Apple')<br>hashCode: 102"]
Node2["对象: new Brand('Google')<br>hashCode: 286"]
Node3["对象: new Brand('Microsoft')<br>hashCode: 470"]
end
subgraph "桶 5 中的内容 (链表结构)"
direction TB
Node4["对象: new Brand('Ford')<br>hashCode: 789"]
Node5["对象: new Brand('Audi')<br>hashCode: 789"]
end
subgraph "桶 6 中的内容 (红黑树结构)"
direction TB
TreeRoot["(根节点)<br>new Brand('Toyota')"]
TreeLeft["(左子节点)<br>new Brand('BYD')"]
TreeRight["(右子节点)<br>new Brand('Honda']"]
TreeRoot --> TreeLeft
TreeRoot --> TreeRight
end
end
%% --- 连接关系 ---
B2 --> Node1
Node1 --> Node2
Node2 --> Node3
B5 --> Node4
Node4 --> Node5
B6 --> TreeRoot
%% --- 样式定义 ---
classDef bucket fill:#e1f5fe,stroke:#01579b,stroke-width:2px,color:#000;
classDef object fill:#fff9c4,stroke:#f57f17,stroke-width:2px,color:#000;
classDef tree fill:#c8e6c9,stroke:#1b5e20,stroke-width:2px,color:#000;
classDef empty fill:#f5f5f5,stroke:#9e9e9e,stroke-width:1px,stroke-dasharray: 5 5,color:#9e9e9e;
class B0,B1,B3,B4,B7,Bn bucket;
class B2,B5,B6 bucket;
class Node1,Node2,Node3,Node4,Node5 object;
class TreeRoot,TreeLeft,TreeRight tree;
class B0,B1,B3,B4,B7,Bn empty;
完整的示例代码
点击查看代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
int n = Integer.parseInt(line);
List<Car> cars = new ArrayList<>();
List<Brand> brands = new ArrayList<>();
for(int i=0;i<n;i++) {
line = scanner.nextLine();
Brand brand = new Brand(line);
if(!brands.contains(brand)) {//应用
brands.add(brand);
cars.add(new Car(brand));
}else {
System.out.println(line+" exists");
}
}
for(Car car:cars) {
System.out.println(car);
}
System.out.println(ArrayList.class.getClassLoader());
scanner.close();
}
}
class Brand{
private String name;
public Brand(String name) {
this.name = name;
}
public String toString() {
return "Brand [name="+name+"]";
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) //判断相同类
{
return false;
}
Brand brand = (Brand) o;
return Objects.equals(name, brand.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
class Car{
int id;
Brand brand;
private static int counter=0;
static {
System.out.println("0 car");
}
public Car(Brand brand) {
this.brand = brand;
this.id = ++counter;
}
public String toString() {
return "Car [id="+id+"brand="+brand.toString()+"]";
}
}

浙公网安备 33010602011771号