一、为什么重写equals()还要重写hashCode()?
这个问题涉及到Java对象的哈希契约(Hash Contract),是Java基础中非常重要的概念。
核心原因
1. 哈希契约要求:Java规定如果两个对象通过equals()比较相等,那么它们的hashCode()必须返回相同的值
2. 集合类依赖:HashMap、HashSet等集合类依赖hashCode()确定存储位置,再用equals()确认键值对
实际示例
class Person {
String name;
int age;
public boolean equals(Object o) {
// 实现内容比较
}
// 必须重写hashCode()
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
不重写的后果
- 可能导致HashMap/HashSet无法正确查找对象
- 可能违反Java集合框架的基本约定
二、==和equals的区别
这是Java中最基础的比较操作,但很多初学者容易混淆。
根本区别
| 比较方式 | == | equals() |
|---------|----|----------|
| 基本类型 | 比较值 | 不可用 |
| 引用类型 | 比较内存地址 | 默认比较地址,可重写为比较内容 |
| 可定制性 | 固定行为 | 可通过重写改变行为 |
经典案例:String比较
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2); // false,地址不同
System.out.println(s1.equals(s2)); // true,内容相同
最佳实践
- 对象内容比较总是使用equals()
- 只在需要确认对象身份时使用==
三、浮点数精度问题:4.0-3.6=0.40000001
这个现象源于计算机表示浮点数的本质限制。
根本原因
1. 二进制表示限制:很多十进制小数无法精确表示为二进制浮点数
2. IEEE 754标准:浮点数存储采用近似值而非精确值
解决方案
1. 精确计算场景:使用BigDecimal
BigDecimal a = new BigDecimal("4.0");
BigDecimal b = new BigDecimal("3.6");
System.out.println(a.subtract(b)); // 精确输出0.4
2. 显示格式化:控制显示精度
double result = 4.0 - 3.6;
System.out.printf("%.1f", result); // 输出0.4
重要原则
- 金融计算绝对不要使用float/double
- 需要精确结果的场景使用BigDecimal
四、final关键字的作用
final在Java中有多种用途,是保证程序稳定性的重要手段。
三种用法
1. final变量:常量,值不可变
final int MAX = 100; // 基本类型值不可变
final List<String> list = new ArrayList(); // 引用不可变,但内容可修改
2. final方法:不可被子类重写
class Parent {
final void show() {} // 子类不能重写此方法
}
3. final类:不可被继承
final class UtilityClass {} // 不能被其他类继承
设计意义
- 提高安全性:防止关键组件被修改
- 明确设计意图:向其他开发者表明不应改变的要素
- 优化可能性:JVM可能对final进行特殊优化
总结
这些面试题看似基础,却涵盖了Java语言设计的核心思想:
1. equals/hashCode体现了对象一致性的重要性
2. ==/equals区分了对象身份与内容的差异
3. 浮点数精度揭示了计算机表示数字的本质限制
4. final关键字展示了Java对安全性和确定性的追求
评论区