开篇:为什么常用类是Java开发的基石?
在Java生态中,常用类如同乐高积木的基础模块。据统计,90%的Java程序会频繁使用String、集合框架和日期处理类。掌握它们不仅能提升开发效率,更是理解面向对象设计思想的绝佳入口。
壹、基本数据类型与包装类
Java中的基本数据类型与包装类是两个密切相关但又有重要区别的概念,主要差异体现在以下几个方面:
-
基本数据类型
- 包括8种:byte(1字节)、short(2字节)、int(4字节)、long(8字节)、float(4字节)、double(8字节)、char(2字节)、boolean(1位)
- 直接存储数据值,分配在栈内存(局部变量时)或堆内存(成员变量时)
- 默认值:数值型为0,boolean为false,char为'\u0000'
- 效率高但功能单一,不支持对象操作
-
包装类
- 对应8种基本类型的对象形式:Byte、Short、Integer、Long、Float、Double、Character、Boolean
- 存储对象的引用,数据实际存在堆内存中
- 默认值为null,可表示"无值"状态
- 提供类型转换、字符串处理等方法(如Integer.parseInt())
-
核心区别
特性 基本类型 包装类 存储方式 直接存储值 存储对象引用 内存占用 固定大小 额外对象开销 泛型支持 不支持 支持 集合使用 不可直接存入 可直接存入 -
自动装箱/拆箱
- Java5+支持自动转换:
Integer i = 100;
(装箱)和int n = i;
(拆箱) - 注意-128~127的Integer缓存机制:
Integer a=127; Integer b=127;
时a==b为true,超出范围则为false
- Java5+支持自动转换:
-
使用场景建议
- 优先基本类型:高性能计算、循环变量、局部变量
- 必须包装类:集合泛型、数据库字段(可能为null)、RPC方法参数
典型问题示例:
List<Integer> list = new ArrayList<>(); // 正确
List<int> list = new ArrayList<>(); // 编译错误
贰、数学与随机工具类
一、Math数学工具类
基础运算方法
绝对值计算:
abs()
系列方法支持多种数据类型取整运算:
•ceil()
向上取整
•floor()
向下取整
•round()
四舍五入极值计算:
min()
/max()
获取最值
高级数学运算
幂运算:
pow(a,b)
计算a的b次方对数运算:
log()
自然对数、log10()
常用对数三角函数:
sin/cos/tan
等标准函数常量字段:
Math.PI
(圆周率)、Math.E
(自然常数)
二、Random随机数类
基础用法
创建实例:
new Random()
使用纳秒级种子
生成随机数:
•nextInt(bound)
生成[0,bound)范围整数
•nextDouble()
生成[0.0,1.0)小数
•nextBoolean()
生成随机布尔值
范围控制技巧
[5,15)范围:
5 + nextInt(10)
[20,30]闭区间:
20 + nextInt(11)
生成随机偶数:
2*(1+nextInt(50))
三、Math.random()方法
特点
静态方法直接调用:
Math.random()
生成[0.0,1.0)范围的double值
转换为整数范围公式:
(int)(Math.random() * (max-min)) + min
四、实用工具类示例
自定义随机数工具类
public class RandomUtil {
private static final Random random = new Random();
public static int nextInt(int min, int max) {
return random.nextInt(max - min + 1) + min;
}
}
五、注意事项
1.Random种子机制
固定种子可复现随机序列:
new Random(12345L)
2.性能比较
Math.random()内部使用Random实例,多线程下可能有竞争需要大量随机数时建议创建单独的Random实例
叁、字符串处理专家——字符串处理三剑客:String、StringBuffer与StringBuilder
一、核心特性对比
特性 | String | StringBuffer | StringBuilder |
---|---|---|---|
可变性 | 不可变(immutable) | 可变(mutable) | 可变(mutable) |
线程安全 | 安全(因不可变) | 安全(同步方法) | 不安全 |
性能 | 低(频繁创建对象) | 中(同步开销) | 高(无同步开销) |
适用场景 | 静态文本处理 | 多线程字符串操作 | 单线程字符串操作 |
String类的不可变性体现在其内部使用final修饰的char数组存储数据,任何修改操作都会创建新对象。而StringBuffer和StringBuilder通过可变的char数组实现高效修改,其中StringBuffer通过synchronized关键字保证线程安全。
二、底层实现机制
String内存模型
// String类部分源码
public final class String {
private final char value[];
// 其他字段和方法...
}
字符串常量池(String Pool)机制使得相同字面量的String对象会共享内存,new String()则会在堆中创建新对象。
StringBuffer/StringBuilder继承关系
abstract class AbstractStringBuilder {
char[] value;
// 非final字符数组
int count;
// 扩容等方法...
}
两者都继承自AbstractStringBuilder,通过动态扩容(默认扩容为原容量*2+2)实现高效修改。
三、性能优化实践
字符串拼接选择
少量拼接:使用String的"+"操作(编译器自动优化为StringBuilder)
循环拼接:必须使用StringBuilder(单线程)或StringBuffer(多线程)
// 错误示范(产生大量中间对象)
String result = "";
for (int i = 0; i < 10000; i++) {
result += i;
}
// 正确做法
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i);
}
初始化容量优化
// 预估最终字符串长度
StringBuilder sb = new StringBuilder(1024);
// 避免多次扩容
四、典型应用场景
String适用场景
配置信息、常量定义
作为HashMap的key(利用不可变性)
方法参数传递(线程安全)
StringBuffer典型用例
// 多线程日志处理
public class Logger {
private StringBuffer logBuffer = new StringBuffer();
public synchronized void log(String message) {
logBuffer.append(LocalDateTime.now())
.append(" - ") .append(message) .append("\n");
}
}
StringBuilder高效操作
// SQL语句构建
public String buildQuery(Map<String, String> params) {
StringBuilder query = new StringBuilder("SELECT * FROM users WHERE 1=1");
params.forEach((k, v) -> { query.append(" AND ")
.append(k) .append(" = '") .append(v)
.append("'"); }); return query.toString();
}
五、最新版本优化建议(Java 17+)
使用Text Block
处理多行字符串
String json = """ { "name": "张三", "age": 25, "address": "北京市" } """;
敏感数据使用char[]
并及时清除
char[] password = getPasswordFromInput();
// 使用后立即清空
Arrays.fill(password, '\0');
考虑使用StringJoiner
简化分隔符拼接
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.add("Java").add("Python").add("Go");
System.out.println(joiner);
// 输出: [Java, Python, Go]
在实际开发中,应根据线程安全需求、性能要求和代码可读性等因素,合理选择这三种字符串处理类。对于现代Java项目,StringBuilder在单线程环境下通常是首选,而String仍是最基础的不可变字符串表示方式。
肆、时间处理类(Java 8+)
一、核心时间处理类概述
-
Date类
- 表示特定瞬间,精确到毫秒
- 大部分方法已被Calendar类取代
- 主要方法:getTime()、after()、before()、compareTo()
-
DateFormat抽象类
- 日期/时间格式化子类的抽象基类
- 提供格式化和解析日期的方法
- 子类SimpleDateFormat实现具体功能
-
SimpleDateFormat类
- 实现日期与文本的相互转换
- 线程不安全(需配合ThreadLocal使用)
- 支持自定义格式模式
-
Calendar抽象类
- 替代Date类进行日期计算
- 提供获取/设置年/月/日等字段的方法
- 常用实现类GregorianCalendar
二、核心功能与使用示例
1. Date基础操作
// 创建Date对象
Date now = new Date(); // 当前时间
Date specific = new Date(1234567890000L); // 指定毫秒数
// 时间比较
boolean isAfter = now.after(specific);
boolean isBefore = now.before(specific);
int compareResult = now.compareTo(specific); // 1:大于 0:等于 -1:小于
2. SimpleDateFormat格式化
// 创建格式化器
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 日期转字符串
String formatted = sdf.format(new Date()); // 输出:2025-08-20 15:21:32
// 字符串转日期
Date parsedDate = sdf.parse("2025-01-01 00:00:00");
3. Calendar日期计算
// 获取Calendar实例
Calendar cal = Calendar.getInstance();
// 设置特定日期
cal.set(2025, Calendar.AUGUST, 20); // 月份从0开始
// 日期加减
cal.add(Calendar.DAY_OF_MONTH, 5); // 加5天
cal.add(Calendar.MONTH, -1); // 减1个月
// 获取字段值
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // 需要+1
int day = cal.get(Calendar.DAY_OF_MONTH);
三、新旧API对比与演进
-
传统API缺陷
- Date设计不合理(年份从1900开始,月份0-11)
- SimpleDateFormat非线程安全
- Calendar操作复杂79
-
Java 8新时间API
- 引入java.time包(LocalDate/LocalTime/LocalDateTime)
- 不可变且线程安全
- 更符合ISO标准
-
新旧API转换
// Date转Instant
Instant instant = new Date().toInstant();
// Instant转LocalDateTime
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
// LocalDateTime转Date
Date oldDate = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
四、最佳实践建议
-
格式化注意事项
- 避免重复创建SimpleDateFormat实例
- 多线程环境使用ThreadLocal包装
- 预编译常用格式模式
-
日期计算推荐
- 简单计算使用Calendar.add()
- 复杂时间操作推荐转为Java 8 API
- 时区处理使用ZonedDateTime
-
性能优化技巧
- 对频繁使用的日期格式进行缓存
- 批量操作时复用Calendar实例
- 考虑使用Joda-Time库(Java 8前)
对于新项目,建议直接采用Java 8的java.time API,传统API仅用于维护旧系统。
伍、枚举类与文件操作类
一、枚举类(Enum)
-
基本定义与特性
- 使用
enum
关键字定义,表示一组固定常量 - 隐式继承
java.lang.Enum
类 - 构造器默认私有,枚举值是
public static final
的实例
- 使用
-
高级特性
public enum FileType { TEXT("txt", "文本文件"), IMAGE("jpg", "图片文件"), AUDIO("mp3", "音频文件"); private final String extension; private final String description; FileType(String ext, String desc) { this.extension = ext; this.description = desc; } // 获取文件类型描述 public String getDescription() { return this.description; } }
- 可包含字段、方法和构造器
- 可实现接口和抽象方法
-
工具类支持
EnumSet
:高性能枚举集合EnumMap
:键为枚举类型的专用Map实现
二、文件操作类(File)
-
File类核心功能
- 文件和目录路径的抽象表示
- 支持三种构造方式:
File file1 = new File("D:/test.txt"); File file2 = new File("D:/", "test.txt"); File parent = new File("D:/"); File file3 = new File(parent, "test.txt");
-
常用方法
- 文件检测:
exists()
,isFile()
,isDirectory()
- 文件操作:
createNewFile()
,delete()
,renameTo()
- 目录操作:
mkdir()
,listFiles()
- 文件检测:
-
递归遍历目录示例
public static void listFiles(File dir) { if (dir == null || !dir.exists()) return; File[] files = dir.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory()) { listFiles(file); // 递归调用 } else { System.out.println(file.getAbsolutePath()); } } } }
三、综合应用示例
结合枚举和文件操作的文件类型检查器:
import java.io.File;
public class FileChecker {
public enum FileCategory {
DOCUMENT(new String[]{"txt", "doc", "pdf"}),
IMAGE(new String[]{"jpg", "png", "gif"}),
AUDIO(new String[]{"mp3", "wav"});
private final String[] extensions;
FileCategory(String[] exts) {
this.extensions = exts;
}
public static FileCategory getCategory(File file) {
String fileName = file.getName();
int dotIndex = fileName.lastIndexOf('.');
if (dotIndex > 0) {
String ext = fileName.substring(dotIndex + 1).toLowerCase();
for (FileCategory category : values()) {
for (String validExt : category.extensions) {
if (validExt.equals(ext)) {
return category;
}
}
}
}
return null;
}
}
public static void main(String[] args) {
File testFile = new File("example.jpg");
FileCategory category = FileCategory.getCategory(testFile);
System.out.println("文件类型: " + (category != null ? category : "未知"));
}
}
该示例展示了:
- 使用枚举定义文件分类标准
- 通过File类获取文件信息
- 实现文件类型自动检测功能
结语:从工具到思想的升华
Java常用类的价值不仅在于API调用,更体现了封装(String的不可变性)、多态(List接口的多种实现)和设计模式(Collections的工厂方法)的经典实践。建议通过三个步骤深化学习:
-
阅读JDK源码注释
-
参与GitHub开源项目
-
尝试重写简化版工具类
程序员箴言:"不会用Java类的开发者就像没有武器的战士——即使面对最简单的任务也会手足无措。"