1. Java常用类概述
Java常用类是Java标准库中那些被高频使用的核心类集合,它们就像是程序员工具箱里的螺丝刀和扳手,几乎每天开发都会用到。我从业十多年来,从新手到架构师,这些类始终是代码中最坚实的基石。不同于框架的快速迭代,常用类历经二十多年Java版本更新依然保持稳定,这种持久性恰恰证明了它们设计的精妙。
在Java开发中,常用类主要分布在以下几个包中:
- java.lang(自动导入):包含最基础的Object、String、包装类等
- java.util:集合框架、日期时间工具等
- java.io:输入输出相关类
- java.math:数学运算类
特别提醒:很多初学者会忽视java.lang包下的类,因为它们不需要显式导入,但这恰恰是最需要深入理解的核心类。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 不可变类的典范:String深度解析
2.1 String的本质与内存机制
String大概是Java中使用频率最高的类了,但它的实现机制却常被误解。底层它就是一个final修饰的char数组:
java复制private final char value[];
这个final关键字就是String不可变的关键。当我们在代码中写:
java复制String s = "hello";
s = s + " world";
实际上创建了三个对象:初始的"hello"、拼接的" world"和最终的"hello world"。
内存优化技巧:
- 对于频繁拼接场景,使用StringBuilder(非线程安全)或StringBuffer(线程安全)
- 使用intern()方法可以将字符串放入字符串常量池,但要注意常量池大小限制
2.2 字符串比较的陷阱
==和equals的区别是老生常谈,但实际开发中依然常见错误:
java复制String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
更隐蔽的是以下情况:
java复制String c = "hello";
String d = "hello";
System.out.println(c == d); // true
这是因为JVM会复用字符串常量池中的对象。
3. 集合框架核心类解析
3.1 ArrayList vs LinkedList
选择哪种List实现取决于操作特征:
- ArrayList:基于动态数组,随机访问O(1),但插入删除平均O(n)
- LinkedList:基于双向链表,插入删除O(1),但随机访问O(n)
扩容机制实战经验:
ArrayList默认初始容量10,扩容时增长50%。对于已知最终大小的集合,建议:
java复制List<String> list = new ArrayList<>(1000); // 避免多次扩容
3.2 HashMap实现原理
JDK8后的HashMap采用数组+链表+红黑树结构,几个关键参数:
- 默认初始容量:16
- 负载因子:0.75(容量达到75%时扩容)
- 树化阈值:链表长度达到8时转为红黑树
哈希冲突解决方案:
java复制final V putVal(int hash, K key, V value) {
// JDK8源码片段
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
// ...
}
实际开发中,合理设置初始容量可以显著提升性能。例如预计存放1000个元素:
java复制Map<String, Object> map = new HashMap<>(1333); // 1000/0.75
4. 时间处理新纪元:从Date到新的时间API
4.1 传统Date的缺陷
SimpleDateFormat不是线程安全的典型例子:
java复制// 错误示例 - 多线程下会抛出异常
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
4.2 Java 8时间API优势
新的java.time包解决了所有老问题:
- Instant:时间戳
- LocalDate:不含时间的日期
- LocalDateTime:含日期和时间
- ZonedDateTime:带时区的时间
日期操作示例:
java复制LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plusWeeks(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String formatted = nextWeek.format(formatter);
5. 包装类与自动装箱拆箱
5.1 缓存机制揭秘
Integer在-128到127之间使用了缓存:
java复制Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false
5.2 性能陷阱
自动装箱拆箱会带来性能损耗:
java复制// 糟糕的写法 - 每次循环都发生装箱
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i; // 自动装箱
}
6. IO类高效使用技巧
6.1 资源关闭的正确姿势
传统的try-catch-finally方式:
java复制FileInputStream fis = null;
try {
fis = new FileInputStream("file.txt");
// 使用流
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
// 处理异常
}
}
}
Java 7后的try-with-resources:
java复制try (FileInputStream fis = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
// 自动关闭资源
}
6.2 缓冲区的魔力
不加缓冲的IO操作就像用滴管转移海水:
java复制// 低效写法
int b;
while ((b = inputStream.read()) != -1) {
outputStream.write(b);
}
// 高效写法
byte[] buffer = new byte[8192]; // 8K缓冲区
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
7. 异常处理最佳实践
7.1 异常分类与选择
- 受检异常(Checked Exception):必须处理的异常,如IOException
- 非受检异常(Unchecked Exception):RuntimeException及其子类
- 错误(Error):系统级错误如OutOfMemoryError
自定义异常建议:
java复制// 业务异常示例
public class OrderNotFoundException extends RuntimeException {
private final String orderId;
public OrderNotFoundException(String orderId) {
super("Order not found: " + orderId);
this.orderId = orderId;
}
public String getOrderId() {
return orderId;
}
}
7.2 异常处理黄金法则
- 不要吞掉异常(空的catch块是罪恶)
- 优先使用最具体的异常类型
- 保留原始异常信息(使用cause参数)
- 异常信息应包含足够上下文
反面教材:
java复制try {
// 业务代码
} catch (Exception e) {
logger.error("Error occurred"); // 丢失了异常细节
}
8. 工具类的高效使用
8.1 Arrays和Collections
数组排序的陷阱:
java复制int[] numbers = {3, 1, 4, 2};
Arrays.sort(numbers); // 正确
String[] strings = {"3", "1", "4", "2"};
Arrays.sort(strings); // 按字典序排序,可能不符合数值预期
Collections的线程安全包装:
java复制List<String> syncList = Collections.synchronizedList(new ArrayList<>());
// 但迭代时仍需手动同步
synchronized (syncList) {
for (String item : syncList) {
// 操作
}
}
8.2 Objects工具类
Java 7引入的Objects类解决了空指针判断的样板代码:
java复制// 传统方式
if (obj != null && obj.equals(other)) {...}
// 使用Objects
if (Objects.equals(obj, other)) {...}
9. 枚举的高级用法
9.1 枚举的本质
枚举编译后实际上是继承Enum的final类:
java复制public enum Color {
RED, GREEN, BLUE
}
// 等价于
public final class Color extends Enum<Color> {
public static final Color RED = new Color();
public static final Color GREEN = new Color();
public static final Color BLUE = new Color();
// ...
}
9.2 枚举实现策略模式
java复制public enum Calculator {
ADD {
@Override
public int apply(int a, int b) {
return a + b;
}
},
SUBTRACT {
@Override
public int apply(int a, int b) {
return a - b;
}
};
public abstract int apply(int a, int b);
}
10. 反射与动态代理
10.1 Class对象的获取方式
java复制Class<?> clazz1 = String.class; // 类字面量
Class<?> clazz2 = Class.forName("java.lang.String"); // 全限定名
Class<?> clazz3 = "hello".getClass(); // 实例方法
10.2 动态代理实战
JDK动态代理示例:
java复制interface Service {
void serve();
}
class RealService implements Service {
public void serve() {
System.out.println("Real service");
}
}
class LoggingHandler implements InvocationHandler {
private final Object target;
public LoggingHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return result;
}
}
// 使用方式
Service proxy = (Service) Proxy.newProxyInstance(
Service.class.getClassLoader(),
new Class[]{Service.class},
new LoggingHandler(new RealService())
);
proxy.serve();
11. 并发工具类解析
11.1 CountDownLatch vs CyclicBarrier
- CountDownLatch:一次性使用,等待多个线程完成
- CyclicBarrier:可重复使用,线程互相等待
典型场景:
java复制// 使用CountDownLatch等待初始化完成
CountDownLatch latch = new CountDownLatch(3);
// 在工作线程中
latch.countDown();
// 在主线程中
latch.await();
// 使用CyclicBarrier实现多阶段任务
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("All threads reached barrier");
});
11.2 ThreadLocal的内存泄漏问题
ThreadLocal使用不当会导致内存泄漏:
java复制// 错误示例
public class UserHolder {
private static ThreadLocal<User> holder = new ThreadLocal<>();
public static void set(User user) {
holder.set(user);
}
// 忘记调用remove()
}
正确做法:
java复制try {
UserHolder.set(currentUser);
// 业务逻辑
} finally {
UserHolder.remove(); // 必须清理
}
12. 新特性:记录类(Record)与文本块
12.1 记录类简化POJO
Java 14引入的record可以替代简单的DTO:
java复制// 传统方式
public class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
// getters, equals, hashCode, toString
}
// 使用record
public record Point(int x, int y) {}
12.2 文本块处理多行字符串
Java 15正式引入的文本块:
java复制// 旧方式
String html = "<html>\n" +
" <body>\n" +
" <p>Hello</p>\n" +
" </body>\n" +
"</html>";
// 文本块方式
String html = """
<html>
<body>
<p>Hello</p>
</body>
</html>
""";
13. 常用工具库推荐
13.1 Apache Commons Lang3
提供各种实用工具方法:
java复制// 字符串操作
StringUtils.isEmpty(str);
StringUtils.join(array, ",");
// 对象操作
Objects.equals(obj1, obj2);
ArrayUtils.contains(array, value);
13.2 Guava的强大集合
java复制// 不可变集合
ImmutableList<String> list = ImmutableList.of("a", "b", "c");
// 多值Map
Multimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.put("key", 1);
multimap.put("key", 2);
// 缓存
LoadingCache<Key, Value> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build(new CacheLoader<Key, Value>() {
public Value load(Key key) {
return createExpensiveValue(key);
}
});
14. 性能优化实战技巧
14.1 对象复用策略
对于重量级对象可以考虑对象池:
java复制// 使用commons-pool2
GenericObjectPool<HeavyObject> pool = new GenericObjectPool<>(
new BasePooledObjectFactory<HeavyObject>() {
@Override
public HeavyObject create() throws Exception {
return new HeavyObject();
}
}
);
// 使用方式
try (HeavyObject obj = pool.borrowObject()) {
// 使用对象
} // 自动归还
14.2 减少临时对象创建
String拼接的优化:
java复制// 低效 - 产生多个临时String对象
String result = "";
for (String part : parts) {
result += part;
}
// 高效 - 使用StringBuilder
StringBuilder sb = new StringBuilder();
for (String part : parts) {
sb.append(part);
}
String result = sb.toString();
15. 调试与问题排查
15.1 阅读栈轨迹的艺术
典型栈轨迹分析:
code复制Exception in thread "main" java.lang.NullPointerException
at com.example.MyClass.process(MyClass.java:42)
at com.example.Main.main(Main.java:10)
关键信息:
- 异常类型:NullPointerException
- 出错位置:MyClass.java第42行
- 调用链:从Main.main开始调用
15.2 内存分析工具
使用VisualVM分析堆内存:
- 启动jvisualvm(JDK自带)
- 连接到目标Java进程
- 使用"抽样器"或"Profiler"选项卡
- 分析内存中的对象分布
常见内存问题:
- 内存泄漏:对象持续增长不释放
- 内存溢出:短时间内创建大量对象
16. 设计模式在常用类中的应用
16.1 迭代器模式
集合的迭代器实现:
java复制List<String> list = Arrays.asList("a", "b", "c");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String element = it.next();
// 处理元素
}
16.2 装饰器模式
IO流中的典型应用:
java复制// 层层装饰
InputStream is = new BufferedInputStream(
new FileInputStream("file.txt"));
17. 编码规范与最佳实践
17.1 命名约定
- 类名:大驼峰,如ArrayList
- 方法名:小驼峰,如getUserName
- 常量:全大写加下划线,如MAX_SIZE
17.2 文档注释规范
java复制/**
* 计算两个数的和
*
* @param a 第一个加数
* @param b 第二个加数
* @return 两数之和
* @throws IllegalArgumentException 当参数为负数时抛出
*/
public int add(int a, int b) {
if (a < 0 || b < 0) {
throw new IllegalArgumentException("参数不能为负");
}
return a + b;
}
18. Java模块化系统
18.1 module-info.java示例
java复制module com.example.myapp {
requires java.base; // 隐式依赖
requires java.logging;
requires transitive com.example.utils; // 传递依赖
exports com.example.myapp.api;
opens com.example.myapp.internal to spring.core;
}
18.2 模块化带来的变化
- 更强的封装性:默认不再允许反射访问非导出包
- 更清晰的依赖关系
- 更小的运行时镜像(通过jlink)
19. 与JVM密切相关的类
19.1 Runtime类
获取JVM信息:
java复制Runtime runtime = Runtime.getRuntime();
System.out.println("可用处理器: " + runtime.availableProcessors());
System.out.println("最大内存: " + runtime.maxMemory() / 1024 / 1024 + "MB");
19.2 System类
常用方法:
java复制long start = System.currentTimeMillis();
// 执行操作
long duration = System.currentTimeMillis() - start;
System.getenv("PATH"); // 获取环境变量
System.getProperty("user.dir"); // 获取系统属性
20. 未来发展趋势
20.1 Valhalla项目:值类型
未来可能引入的值类型:
java复制// 可能语法(尚未正式发布)
value class Point {
int x;
int y;
}
20.2 Loom项目:虚拟线程
轻量级线程的简化:
java复制Thread.startVirtualThread(() -> {
// 任务代码
});
这些常用类构成了Java开发的基石,深入理解它们不仅能写出更好的代码,还能在面试中展现扎实的基本功。我建议初学者可以按照以下路线深入学习:
- 先掌握每个类的常用API
- 然后研究其实现原理
- 最后思考设计者的意图和取舍
在实际项目中,合理使用这些类可以避免重复造轮子,提高开发效率。比如用Collections.unmodifiableList返回不可变列表,用Objects.requireNonNull进行参数校验,用StringJoiner拼接字符串等。记住,优秀的Java程序员不是知道最多框架的人,而是能把这些基础类用到极致的人。
