Java基础速成:集合、String与异常处理核心要点
Java基础速成:集合、String与异常处理核心要点
引言
在Java技术栈的面试与实际开发中,基础知识的扎实程度往往决定了一个开发者的上限。无论是构建高并发的后端服务,还是编写健壮的中间件组件,集合框架、字符串处理以及异常处理机制都是不可或缺的基石。
很多开发者能够熟练使用ArrayList和HashMap,却在使用过程中无意间埋下了性能隐患或Bug;对String的不可变性一知半解,导致在拼接字符串时效率低下;对异常处理机制理解不透彻,使得系统在出错时难以定位问题。
本文将跳出简单的API罗列,从底层原理、源码实现、性能优化及实战陷阱四个维度,深度剖析这三大核心模块,助你构建完整的Java知识体系。
一、 集合框架:数据容器的艺术
Java集合框架主要分为Collection和Map两大体系。面试中,重点在于理解不同容器的底层数据结构及其在多线程环境下的表现。
1.1 List体系:ArrayList与LinkedList的抉择
核心原理:
* ArrayList:基于动态数组实现。它允许通过下标快速随机访问,但插入和删除元素可能涉及数组的移动(复制),效率较低。其扩容机制是重点:默认初始容量为10,当空间不足时,按照1.5倍扩容(int newCapacity = oldCapacity + (oldCapacity >> 1)),并调用Arrays.copyOf进行数据搬运。
* LinkedList:基于双向链表实现。插入删除只需修改指针,时间复杂度为O(1)(已知节点),但随机访问需要遍历链表,时间复杂度为O(n)。
实战误区:
很多开发者认为“删除操作多就用LinkedList”。实际上,由于现代CPU缓存机制的存在,数组连续内存空间的访问速度远快于链表的非连续内存访问。除非涉及大量的头插/头删操作,否则绝大多数业务场景下ArrayList性能更优。
1.2 Map体系:HashMap的底层演进
HashMap是面试的“王者”考点。
JDK 1.8 之前: 数组 + 链表。Hash冲突时,节点形成链表。
JDK 1.8 之后: 数组 + 链表 + 红黑树。
核心原理深度解析:
1. 初始化:默认初始容量16,负载因子0.75。当元素个数 > 容量 * 负载因子时,触发扩容。
2. 哈希计算:为了减少哈希冲突,HashMap对Key的hashCode进行了扰动处理:(h = key.hashCode()) ^ (h >>> 16)。高16位异或低16位,使得低位特征中掺杂了高位特征,从而在取模运算(n-1 & hash)时分布更均匀。
3. 树化阈值:当链表长度超过8且数组长度超过64时,链表会转化为红黑树,将查询复杂度从O(n)降低到O(log n)。
1.3 实战代码示例:自定义Key的陷阱
在实际项目中,常用对象作为Map的Key。如果重写equals但不重写hashCode,会导致内存泄漏或查询失败。
import java.util.HashMap;
import java.util.Objects;
/**
* 演示HashMap中作为Key的对象必须重写equals和hashCode方法
*/
class User {
private String name;
private int id;
public User(String name, int id) {
this.name = name;
this.id = id;
}
// 必须重写equals,否则比较的是内存地址
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id == user.id && Objects.equals(name, user.name);
}
// 必须重写hashCode,否则相同的对象可能计算出不同的哈希槽位
@Override
public int hashCode() {
return Objects.hash(name, id);
}
}
public class CollectionDemo {
public static void main(String[] args) {
HashMap<User, String> map = new HashMap<>();
User u1 = new User("Alice", 101);
map.put(u1, "Admin");
// 即使是new出来的新对象,因为重写了equals和hashCode,依然能取到值
User u2 = new User("Alice", 101);
System.out.println("获取用户角色: " + map.get(u2)); // 输出: Admin
// 如果不重写hashCode,u2的hash值与u1不同,将返回null
// 如果不重写equals,即使hash碰撞,equals比较也会失败
}
}
二、 String:不可变性的设计哲学
String是Java中使用频率最高的类,也是面试中最容易忽视深度的部分。
2.1 不可变性
String被final修饰,且内部存储字符的数组(JDK 8是char[],JDK 9是byte[])也是final的。这意味着String对象一旦创建,其值不可更改。
为什么设计成不可变?
1. 字符串常量池优化:Java将字符串字面量存储在常量池中。如果String可变,改变一个引用指向的字符串,会导致所有指向该字符串的引用都发生变化,这将是灾难性的。
2. 线程安全:不可变对象

浙公网安备 33010602011771号