应使用ArrayList而非数组,因其自动扩容、类型安全;需重写equals/hashCode、避免遍历时直接remove、预估容量初始化、谨慎选用TreeSet排序、推荐JSON序列化并处理兼容性。

为什么用 ArrayList 而不是数组存联系人
数组长度固定,增删联系人时得手动复制、扩容,容易出错;ArrayList 自动处理这些,且支持泛型约束类型安全。别写 Object[] 或 Contact[] —— 后者删一个元素就得自己移动后续所有引用,ArrayList.remove(int) 已经帮你做了。
注意点:
-
ArrayList查找慢(O(n)),如果频繁按姓名查,后面得补HashMap索引 - 别在遍历
ArrayList时直接调用remove(),会抛ConcurrentModificationException;改用Iterator.remove()或倒序 for 循环 - 初始化别写
new ArrayList()就完事——预估联系人上限(比如 200),写成new ArrayList(200),避免多次扩容拷贝
Contact 类必须重写 equals() 和 hashCode()
否则用 list.contains(new Contact("张三")) 永远返回 false,因为默认比较的是内存地址。只要 name 和 phone 相同就认为是同一人,就得按这两个字段生成哈希码。
示例关键片段:
立即学习“Java免费学习笔记(深入)”;
public class Contact {
private String name;
private String phone;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Contact contact = (Contact) o;
return Objects.equals(name, contact.name) &&
Objects.equals(phone, contact.phone);
}
@Override
public int hashCode() {
return Objects.hash(name, phone);
}
}
别漏掉 Objects 工具类——它自动处理 null 安全,比手写 name != null ? name.hashCode() : 0 更可靠。
用 TreeSet 实现自动排序通讯录
如果希望每次添加后联系人按姓名拼音或字母序排列,不用每次 Collections.sort(),直接用 TreeSet,但前提是 Contact 实现 Comparable 接口。
常见陷阱:
- 别只按
name字段比较——万一重名呢?得加phone作为第二排序条件,否则TreeSet会把两个同名不同号的人当成重复项丢掉 - 别在
compareTo()里调用String.toUpperCase()做忽略大小写比较——中文拼音排序会乱,改用Collator.getInstance(Locale.CHINA) -
TreeSet不允许null元素,插入前务必检查contact != null
从文件读写联系人时,Serializable 不是唯一选择
用 ObjectOutputStream 写 ArrayList 是最直白的方式,但二进制格式不跨 Java 版本、不可读、难调试。实际开发中更推荐 JSON:
- 用
Gson或Jackson库,一行就能序列化:gson.toJson(contacts, new TypeToken- >(){}.getType())
- JSON 文件可人工编辑、Git 可 diff、前端也能直接解析
- 若坚持用
Serializable,记得给Contact加private static final long serialVersionUID = 1L;,否则类结构稍变(比如加个字段)反序列化就失败
文件路径别硬编码 "contacts.dat",用 System.getProperty("user.home") + "/contacts.json" 更稳妥。
真正麻烦的不是存取逻辑,而是字段变更后的兼容性——比如某天加了 email 字段,旧 JSON 文件没这字段,Gson 默认会设为 null,但你的业务代码得能容忍这个 null。










