很多 Java 开发者栽跟头,不是因为不会复杂算法,而是栽在看似 "不起眼" 的基础知识点上 ------ 比如 equals 和 hashCode 的绑定关系、接口默认方法冲突、try-with-resources 的正确用法。今天用 "原理 + 代码" 拆解,帮你避开这些进阶路上的 "隐形绊脚石"!
1. equals 和 hashCode:必须成对重写,不然 Map/Set 要 "罢工"
坑点 :只重写 equals 方法,却忽略 hashCode,导致对象存入 HashMap 后找不到?核心规则:equals 相等的对象,hashCode 必须相等;hashCode 相等的对象,equals 不一定相等(避免哈希冲突)。
java
import java.util.HashMap;
public class EqualsHashCodeTest {
private String id;
public EqualsHashCodeTest(String id) {
this.id = id;
}
// 重写equals:判断id相等则对象相等
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EqualsHashCodeTest that = (EqualsHashCodeTest) o;
return id.equals(that.id);
}
// 必须重写hashCode:和equals逻辑一致,基于id计算
@Override
public int hashCode() {
return id.hashCode();
}
public static void main(String[] args) {
HashMap<EqualsHashCodeTest, String> map = new HashMap<>();
EqualsHashCodeTest obj1 = new EqualsHashCodeTest("1001");
EqualsHashCodeTest obj2 = new EqualsHashCodeTest("1001");
map.put(obj1, "张三");
System.out.println(map.get(obj2)); // 输出:张三(如果没重写hashCode,会输出null)
}
}
2. 接口默认方法冲突:多实现时该听谁的?
坑点 :一个类实现多个接口,接口都有同名默认方法,编译报错不知道怎么解决?解决规则:子类必须重写冲突的默认方法,手动指定实现逻辑(或调用某个接口的默认方法)。
java
// 接口A:含默认方法say()
interface InterfaceA {
default void say() {
System.out.println("我是接口A");
}
}
// 接口B:含同名默认方法say()
interface InterfaceB {
default void say() {
System.out.println("我是接口B");
}
}
// 实现两个接口,必须重写冲突的say()
class MyClass implements InterfaceA, InterfaceB {
@Override
public void say() {
// 方案1:自定义实现
System.out.println("我是MyClass,自己的实现");
// 方案2:调用某个接口的默认方法(二选一)
// InterfaceA.super.say();
// InterfaceB.super.say();
}
}
public class DefaultMethodTest {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.say(); // 输出:我是MyClass,自己的实现
}
}
3. try-with-resources:自动关闭资源,比 finally 更优雅
坑点 :用 finally 关闭流 / 连接时,代码冗余还容易漏处理异常?核心优势 :try-with-resources 会自动关闭实现了AutoCloseable接口的资源(如流、Socket),代码更简洁,异常处理更完善。
java
import java.io.FileInputStream;
import java.io.IOException;
public class TryWithResourcesTest {
// 传统方式:finally关闭资源(代码冗余)
public static void readFileOld(String path) {
FileInputStream fis = null;
try {
fis = new FileInputStream(path);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 优雅方式:try-with-resources自动关闭
public static void readFileNew(String path) {
// 资源声明在try括号内,自动关闭,无需finally
try (FileInputStream fis = new FileInputStream(path)) {
// 读取文件操作
} catch (IOException e) {
System.err.println("文件操作异常:" + e.getMessage());
}
}
public static void main(String[] args) {
readFileNew("test.txt");
}
}
总结:基础进阶 = 避开坑 + 用对技巧
这 3 个知识点看似 "细节",却直接影响代码的正确性和优雅度!记住:
- 重写 equals 必重写 hashCode,否则集合类出问题;
- 多接口默认方法冲突,子类必须手动解决;
- 资源关闭优先用 try-with-resources,简洁又安全。