深入解析:Java 进阶: hashCode/equals 与异常处理深度解析
Java-day17
一、hashCode 与 equals 方法:对象去重的核心逻辑
1.1 hashCode 与 equals 的关系
在 Java 中,hashCode() 和 equals() 是对象去重、集合判重的核心方法,二者需同时重写以保证逻辑一致性:
- equals() 用于判断两个对象“逻辑上是否相等”;
- hashCode() 用于生成对象的哈希码,集合(如 HashSet、HashMap)会先通过哈希码快速定位,再通过 equals() 确认是否重复。
**规则**:
- 若 a.equals(b) == true,则 a.hashCode() == b.hashCode() 必须成立;
- 若 a.hashCode() != b.hashCode(),则 a.equals(b) == false 必然成立;
- 若 a.hashCode() == b.hashCode(),a.equals(b) 可能为 true 或 false(哈希冲突)。
1.2 实战:未正确重写 hashCode 导致的去重失败
```java
class Dog {
private String name;
public Dog(String name) {
this.name = name;
}
// 仅重写 equals,未重写 hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dog dog = (Dog) o;
return name.equals(dog.name);
}
@Override
public String toString() {
return "Dog{name='" + name + "'}";
}
}
public class HashSetDemo {
public static void main(String[] args) {
HashSet hashSet = new HashSet<>();
Dog dog1 = new Dog("小花");
Dog dog2 = new Dog("小花");
System.out.println(dog1.equals(dog2)); // 输出:true
hashSet.add(dog1);
hashSet.add(dog2);
System.out.println(hashSet); // 输出:[Dog{name='小花'}, Dog{name='小花'}](去重失败)
}
}
```
**原因**:Dog 类未重写 hashCode(),默认使用 Object 类的哈希实现(基于对象内存地址),导致 dog1 和 dog2 哈希码不同,HashSet 认为是两个不同对象。
1.3 正确重写 hashCode 与 equals
```java
class Dog {
private String name;
public Dog(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dog dog = (Dog) o;
return name.equals(dog.name);
}
@Override
public int hashCode() {
return name.hashCode(); // 基于 name 生成哈希码
}
@Override
public String toString() {
return "Dog{name='" + name + "'}";
}
}
public class HashSetDemo {
public static void main(String[] args) {
HashSet hashSet = new HashSet<>();
Dog dog1 = new Dog("小花");
Dog dog2 = new Dog("小花");
System.out.println(dog1.equals(dog2)); // 输出:true
hashSet.add(dog1);
hashSet.add(dog2);
System.out.println(hashSet); // 输出:[Dog{name='小花'}](去重成功)
}
}
```
二、Java 异常体系:问题的分类与处理
2.1 异常体系结构
Java 异常体系的根类是 Throwable,分为两大分支:
- **Error**:程序无法处理的错误(如 StackOverflowError、OutOfMemoryError),由 JVM 抛出,通常导致程序终止;
- **Exception**:程序可处理的异常,分为:
- **运行时异常(非受检异常)**:由逻辑错误导致(如 ArrayIndexOutOfBoundsException),编译期不强制处理;
- **受检异常(非运行时异常)**:编译期强制处理的异常(如 IOException、ClassNotFoundException)。
2.2 异常处理方式
(1)try-catch-finally:捕获并处理异常
```java
public class TryCatchDemo {
public static void main(String[] args) {
try {
// 可能抛出异常的代码
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// 处理异常
e.printStackTrace();
} finally {
// 无论是否异常,都会执行的代码(如资源关闭)
System.out.println("finally 代码块");
}
// 异常处理后,后续代码仍会执行
System.out.println("程序继续运行");
}
}
```
(2)throws:声明方法可能抛出的异常
```java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ThrowsDemo {
// 声明方法可能抛出的受检异常
public static void readFile(String filePath) throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream(filePath);
int data = fis.read();
fis.close();
}
public static void main(String[] args) {
try {
readFile("test.txt");
} catch (FileNotFoundException e) {
System.out.println("文件未找到");
} catch (IOException e) {
System.out.println("IO 错误");
}
}
}
```
```(3)throw:主动抛出异常对象
```java
public class ThrowDemo {
public static void main(String[] args) {
try {
// 主动抛出异常
throw new Exception("自定义异常信息");
} catch (Exception e) {
System.out.println(e.getMessage()); // 输出:自定义异常信息
}
}
}
```
2.3 常见异常场景与处理
(1)运行时异常(逻辑错误)
```java
public class RuntimeErrorDemo {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
try {
// 数组越界异常(运行时异常)
System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组索引越界:" + e.getMessage());
}
}
}
```
(2)栈溢出错误(Error)
```java
public class StackOverflowDemo {
public static void test1() {
test1(); // 递归调用自身,导致栈溢出
}
public static void main(String[] args) {
try {
test1();
} catch (StackOverflowError e) {
System.out.println("栈溢出错误:" + e.getMessage());
}
}
}
```
三、总结:hashCode/equals 与异常处理核心要点
1. **hashCode 与 equals**:
- 必须同时重写以保证集合去重逻辑正确;
- 遵循“equals 为 true 则 hashCode 必须相等”的规则。
2. **异常处理**:
- try-catch-finally 用于捕获并处理异常,保证程序不中断;
- throws 用于声明方法的异常风险,由调用者处理;
- throw 用于主动抛出异常,实现自定义错误逻辑;
- 区分 Error(无法处理)和 Exception(可处理),以及“运行时异常”和“受检异常”的场景差异。
通过本文的学习,你已掌握 Java 中对象去重的核心逻辑(hashCode/equals)和异常处理的完整流程。在实际开发中,正确重写 hashCode/equals 是集合操作的基础,而合理的异常处理则是保证程序健壮性的关键。
浙公网安备 33010602011771号