一、为什么重写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对安全性和确定性的追求