Java基础全套教程(五)—— 常用类精讲
Java基础全套教程(五)—— 常用类精讲
前面章节我们掌握了Java数组、多维数据存储、基础算法等核心内容,具备了基础代码编写能力。本章将聚焦Java高频核心常用类,这类类库是JDK原生提供的基础工具,贯穿所有Java项目开发、笔试面试,是日常编码使用率最高的核心内容。
本章将系统讲解包装类、字符串体系类、时间处理类、数学工具类、随机数类、文件操作类、枚举类,搭配全新原创案例、底层原理、开发陷阱与实战场景,帮大家彻底吃透Java基础常用类,告别只会调用不会原理的编程短板。
本章学习目标
-
掌握八大基本数据类型对应包装类的映射关系、核心作用与底层原理;
-
精通自动装箱、自动拆箱机制,掌握包装类缓存机制与面试高频坑点;
-
深度区分String、StringBuilder、StringBuffer的特性、性能差异与使用场景;
-
熟练掌握Date、SimpleDateFormat、Calendar时间类的使用与时间格式化、计算逻辑;
-
掌握Math、Random工具类的常用方法,实现数学计算、随机数生成等场景;
-
熟练使用File类操作文件与目录,掌握递归遍历目录树的实战写法;
-
理解枚举类的底层本质、使用场景,掌握枚举常量的基础用法。
5.1 基本数据类型包装类
5.1.1 包装类核心概念
Java是面向对象编程语言,但八大基本数据类型(byte、short、int、long、float、double、char、boolean)不属于对象,没有属性和方法,无法参与对象类型操作(如存入Object数组、集合存储、泛型使用等)。
为了解决基本类型不具备对象特性的问题,JDK为每一种基本数据类型,提供了对应的包装类(Wrapper Class),核心作用是将基本数据类型封装为对象,让基本类型可以完全适配面向对象的所有操作场景。
补充核心知识点:
-
所有包装类均位于
java.lang包,无需手动导包,开箱即用; -
所有包装类都是不可变类,对象创建后,内部数值无法修改;
-
JDK9 及以上版本废弃了所有包装类的构造方法,强制推荐静态方法创建对象;
-
包装类是集合、泛型、对象传参的必备基础,项目中无法脱离包装类开发。
5.1.2 基本类型与包装类映射关系
八大基本类型与包装类一一对应,整体命名规则统一,仅两个特殊类名,是日常开发、笔试的基础记忆点:
常规规则:基本类型首字母大写即为对应包装类;
特殊规则:int→Integer、char→Character(完整单词拼写)。
| 基本数据类型 | 对应包装类 | 所属分类 |
|---|---|---|
| byte | Byte | 数值型(继承Number) |
| short | Short | 数值型(继承Number) |
| int | Integer | 数值型(继承Number) |
| long | Long | 数值型(继承Number) |
| float | Float | 数值型(继承Number) |
| double | Double | 数值型(继承Number) |
| char | Character | 字符型(独立类) |
| boolean | Boolean | 布尔型(独立类) |
5.1.3 Number抽象类详解
Number类是所有数值型包装类的顶层抽象父类,位于 java.lang 包,专门用于统一所有数值类型的转换规范。Byte、Short、Integer、Long、Float、Double 均直接继承 Number 类。
底层原理:
Number 作为抽象类,定义了一套强制子类实现的抽象方法,统一了数值类型转换标准,让所有数值包装类具备互通转换的能力,解决了不同数值类型转换混乱的问题。
核心抽象方法(所有数值包装类全部重写实现):
-
intValue():将包装类对象转为int基本类型
-
longValue():将包装类对象转为long基本类型
-
floatValue():将包装类对象转为float基本类型
-
doubleValue():将包装类对象转为double基本类型
实战用途:接收任意数值包装对象,统一完成数值转型,适配各类业务计算、数据接收场景。
5.1.4 包装类基础使用(全新案例)
版本规范知识点:JDK9 开始,包装类构造方法被废弃、标记为过时,官方彻底不推荐 new Integer() 方式创建对象,优先使用valueOf() 静态方法,效率更高、支持缓存、更安全。
包装类四大核心使用场景:
- 基本类型与包装对象互转;2. 字符串与数值类型互转;3. 获取数值类型极值常量;4. 类型判断与进制转换。
public class WrapperBaseDemo {
public static void main(String[] args) {
// 1. 基本类型转包装对象(官方推荐写法)
Integer numObj = Integer.valueOf(666);
Double doubleObj = Double.valueOf(99.9);
// 2. 包装对象转基本类型
int num = numObj.intValue();
double doubleNum = doubleObj.doubleValue();
// 3. 字符串转数值包装对象(业务高频:前端传字符串数字、配置文件读取数字)
Integer strToInt = Integer.parseInt("123");
Double strToDouble = Double.parseDouble("88.88");
// 4. 获取数值核心常量(最大值、最小值、精度常量)
System.out.println("int类型最大值:" + Integer.MAX_VALUE);
System.out.println("int类型最小值:" + Integer.MIN_VALUE);
System.out.println("double类型精度:" + Double.PRECISION);
// 打印转换结果
System.out.println("包装对象转基本数值:" + num);
System.out.println("字符串转数字:" + strToInt + "、" + strToDouble);
}
}
补充易错点:parseXXX 方法只能转换纯数字字符串,包含字母、符号、空格会直接抛出 NumberFormatException 数字格式异常。
5.2 自动装箱与自动拆箱(核心重点)
5.2.1 核心概念
JDK5 版本新增自动装箱、自动拆箱机制,属于编译器层面的语法糖,无需开发者手动调用转换方法,编译器在编译阶段自动完成基本类型与包装类对象的互转,极大简化代码编写。
自动装箱:基本类型自动转为包装类对象,底层默认调用包装类.valueOf() 方法
自动拆箱:包装类对象自动转为基本类型,底层默认调用 xxxValue() 方法
核心本质:代码层面简化,底层依旧是手动转换方法,只是编译器帮我们自动补全代码。
5.2.2 代码实战与底层解析
public class AutoBoxDemo {
public static void main(String[] args) {
// 自动装箱:编译器自动编译为 Integer age = Integer.valueOf(18);
Integer age = 18;
Integer score = 95;
// 自动拆箱:编译器自动编译为 int a = age.intValue();
int a = age;
int b = score;
// 运算时自动拆箱计算:先拆箱为基本类型,再运算
int sum = age + score;
System.out.println("数值求和:" + sum);
// 空指针异常经典场景(面试高频)
Integer data = null;
// int res = data; // 运行报错:NullPointerException
// 底层原理:data.intValue(),null对象无法调用方法
}
}
开发必避坑知识点:
包装类是引用类型,默认可以为 null;基本类型不能为空。当包装类对象为 null 时,直接拆箱赋值给基本类型,会触发空指针异常。业务代码中,所有包装类参数必须先做非空判断再使用。
5.2.3 包装类缓存机制(面试必考)
为提升运行性能、减少频繁创建对象造成的内存浪费,JDK 为数值型包装类(Integer、Short、Long、Byte)实现了静态缓存机制。
缓存规则:自动装箱时,数值在 -128 ~ 127 区间内,直接复用缓存中预创建的对象;超出该区间,每次都会 new 新对象。
底层原理:类加载阶段,JDK 自动初始化 cache 数组,预加载 -128~127 所有数值的包装对象,常驻内存,后续直接复用引用地址。
不支持缓存的类:Float、Double、Boolean、Character 无缓存机制。
缓存机制实战测试
public class WrapperCacheDemo {
public static void main(String[] args) {
// 区间内:复用缓存对象,引用地址相同
Integer n1 = 100;
Integer n2 = 100;
System.out.println("100 == 100:" + (n1 == n2)); // true
System.out.println("数值相等:" + n1.equals(n2)); // true
// 区间外:新建两个对象,引用地址不同
Integer n3 = 200;
Integer n4 = 200;
System.out.println("200 == 200:" + (n3 == n4)); // false
System.out.println("数值相等:" + n3.equals(n4)); // true
// 负数区间缓存测试
Integer m1 = -128;
Integer m2 = -128;
System.out.println("-128 == -128:" + (m1 == m2)); // true
}
}
面试&开发核心总结:
包装类数值比较,一律使用 equals() 方法,禁止使用 。 比较的是对象地址,equals 比较的是真实数值,彻底规避缓存机制带来的判断误差。
5.3 字符串核心类(String、StringBuilder、StringBuffer)
5.3.1 三类字符串核心特性对比
Java 字符串体系三大核心类是开发、面试高频考点,三者在可变性、线程安全、性能、使用场景上差异极大,必须精准区分:
-
String:不可变字符序列,线程安全,频繁修改性能极低,适合固定不变的字符串
-
StringBuilder:可变字符序列,线程不安全,性能极高,单线程环境优先使用
-
StringBuffer:可变字符序列,线程安全,性能较低,多线程并发环境使用
核心本质区别:String 每次修改产生新对象;后两者直接修改原字符数组,不产生新对象。
5.3.2 String不可变原理与陷阱
不可变底层原理:
String 底层依靠 private final char[] value 存储字符内容,final 修饰数组地址不可被重新赋值,因此 String 对象一旦初始化成功,内部字符内容永久无法修改。
所有对 String 的修改操作(拼接、截取、替换、转大小写)都不会修改原对象,而是重新创建一个新的字符串对象,原对象保留在内存中,极易造成内存冗余。
String拼接底层陷阱演示
public class StringImmutableDemo {
public static void main(String[] args) {
String str = "Java";
// 拼接操作生成新对象,原对象不变
str += "编程";
str += "入门";
// 常量拼接:编译器优化,编译期直接合并为一个字符串
String s1 = "Hello" + "World";
String s2 = "HelloWorld";
System.out.println(s1 == s2); // true
// 变量拼接:运行期动态生成新对象,无编译优化
String a = "Hello";
String b = "World";
String s3 = a + b;
System.out.println(s2 == s3); // false
}
}
核心陷阱知识点:
-
纯常量拼接:编译期优化,直接合并,无性能损耗;
-
含变量拼接:运行期创建新对象,循环中使用会造成严重性能问题;
-
String 不可变特性保证了线程安全、字符串常量池复用,适合固定文本。
5.3.3 StringBuilder/StringBuffer 可变字符串实战
可变字符串类底层为可变字符数组,所有增删改操作均直接修改原数组内容,不生成新对象,性能远高于 String,是频繁字符串操作的开发标准。
核心通用方法:append()追加、delete()删除、insert()插入、reverse()反转、toString()转String。
public class StringBuildDemo {
public static void main(String[] args) {
// 初始化可变字符串
StringBuilder sb = new StringBuilder();
// 批量追加内容(链式编程)
sb.append("2026")
.append("年")
.append("Java基础教程");
System.out.println("拼接后:" + sb);
// 插入内容:指定下标插入
sb.insert(4, "最新");
System.out.println("插入后:" + sb);
// 删除指定区间内容 [start,end)
sb.delete(0, 4);
System.out.println("删除后:" + sb);
// 字符串反转
sb.reverse();
System.out.println("反转后:" + sb);
}
}
5.3.4 字符串性能对比实战
循环场景下 String 会疯狂创建临时对象,占用内存、效率极低;StringBuilder 全程操作一个对象,性能碾压 String。
public class StringPerformanceDemo {
public static void main(String[] args) {
// String 循环拼接测试
long start1 = System.currentTimeMillis();
String str = "";
for (int i = 0; i < 10000; i++) {
str += i;
}
long end1 = System.currentTimeMillis();
System.out.println("String耗时:" + (end1 - start1) + "ms");
// StringBuilder 循环拼接测试
long start2 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i);
}
long end2 = System.currentTimeMillis();
System.out.println("StringBuilder耗时:" + (end2 - start2) + "ms");
}
}
开发强制规范:
固定不变的字符串用 String;单线程频繁拼接、循环拼接优先用 StringBuilder;多线程并发拼接场景使用 StringBuffer。
5.4 时间处理核心类
5.4.1 Date 时间类
java.util.Date 是Java传统时间核心类,核心作用是封装毫秒时间戳,以 1970-01-01 00:00:00(格林威治时间)为基准时间,通过毫秒差值计算当前时间。
知识点补充:Date 大部分年月日时分秒的赋值方法已被废弃,仅保留获取时间戳、时间对比的核心方法。
import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
// 获取当前系统时间
Date now = new Date();
System.out.println("当前时间:" + now);
// 获取当前时间毫秒时间戳
long timeStamp = now.getTime();
System.out.println("当前时间戳:" + timeStamp);
// 根据时间戳构建指定时间
Date oldDate = new Date(1719820800000L);
System.out.println("指定时间戳对应时间:" + oldDate);
}
}
5.4.2 SimpleDateFormat 时间格式化
Date 默认输出格式不符合国内业务习惯,SimpleDateFormat 专门解决时间格式化问题,实现两大核心功能:时间对象转自定义格式字符串、字符串转Date时间对象。
常用时间格式符
yyyy(年)、MM(月)、dd(日)、HH(24小时制)、hh(12小时制)、mm(分钟)、ss(秒)
易错点:月份是大写 MM,分钟是小写 mm,大小写不可混淆。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatDemo {
public static void main(String[] args) throws ParseException {
// 定义格式化模板
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 时间对象转格式化字符串(格式化)
String nowTime = sdf.format(new Date());
System.out.println("格式化当前时间:" + nowTime);
// 字符串转时间对象(解析)
String timeStr = "2026-05-13 18:30:00";
Date date = sdf.parse(timeStr);
System.out.println("字符串转时间对象:" + date);
}
}
开发坑点:SimpleDateFormat 线程不安全,多线程环境下禁止共享同一个对象。
5.4.3 Calendar 日历工具类
Calendar 是抽象日历工具类,用于替代 Date 废弃的日期操作方法,支持灵活的时间获取、时间加减、日期修改,是传统Java日期计算核心类。
核心底层知识点:
-
Calendar 是抽象类,无法直接 new,通过静态方法获取实例或 new 子类 GregorianCalendar;
-
月份取值范围 0~11:0代表1月,11代表12月,使用必须+1修正;
-
周日为一周的第一天,和国内习惯不同。
import java.util.Calendar;
import java.util.GregorianCalendar;
public class CalendarDemo {
public static void main(String[] args) {
// 获取日历对象
Calendar calendar = new GregorianCalendar();
// 获取当前年月日、时分秒
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // 月份+1修正
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
System.out.println("当前日期:" + year + "年" + month + "月" + day + "日 " + hour + "点");
// 时间计算:往后推10天
calendar.add(Calendar.DAY_OF_MONTH, 10);
System.out.println("10天后日期:" + (calendar.get(Calendar.MONTH)+1) + "月" + calendar.get(Calendar.DAY_OF_MONTH) + "日");
}
}
5.5 数学与随机数工具类
5.5.1 Math 数学工具类
java.lang.Math 是静态工具类,构造方法私有,无法实例化,所有属性、方法均为静态,直接通过类名调用。提供开发中所有常用的数学计算功能,适配绝大多数数值运算场景。
核心分类:取整运算、绝对值、幂运算、开方、最值、三角函数、数学常量、随机数。
public class MathDemo {
public static void main(String[] args) {
// 取整操作
System.out.println("向上取整4.1:" + Math.ceil(4.1)); // 向上取整,向大数靠拢
System.out.println("向下取整4.9:" + Math.floor(4.9)); // 向下取整,向小数靠拢
System.out.println("四舍五入4.5:" + Math.round(4.5)); // 四舍五入
// 基础计算
System.out.println("绝对值:" + Math.abs(-99));
System.out.println("8的平方:" + Math.pow(8, 2));
System.out.println("16的平方根:" + Math.sqrt(16));
System.out.println("最大值:" + Math.max(22, 88));
// 数学常量
System.out.println("圆周率:" + Math.PI);
}
}
5.5.2 Random 随机数类
java.util.Random 是专业随机数生成类,相比 Math.random() 功能更全面、可控性更强,支持自定义整数区间、小数、布尔值随机生成,是业务开发首选。
随机区间计算公式:起始值 + random.nextInt(差值+1)
import java.util.Random;
public class RandomDemo {
public static void main(String[] args) {
Random random = new Random();
// 生成0-9随机整数
int num1 = random.nextInt(10);
System.out.println("0-9随机数:" + num1);
// 生成20-50随机整数(区间计算:起始值 + nextInt(区间差值))
int num2 = 20 + random.nextInt(31);
System.out.println("20-50随机数:" + num2);
// 随机小数、布尔值
System.out.println("随机小数:" + random.nextDouble());
System.out.println("随机布尔值:" + random.nextBoolean());
}
}
知识点补充:Random 基于种子生成随机数,种子相同则随机数序列相同,属于伪随机数。
5.6 File 文件操作类
5.6.1 File类核心作用
java.io.File 是Java文件操作核心类,用于操作文件和文件夹的路径与属性,可以实现文件/目录的创建、删除、查询、遍历。
核心区分知识点:File 类仅操作文件属性、路径、状态,不具备读取、写入文件内容的能力,文件内容读写需要后续IO流实现。
5.6.2 文件基础操作实战
import java.io.File;
import java.util.Date;
public class FileBaseDemo {
public static void main(String[] args) throws Exception {
// 1. 创建文件(相对路径:项目根目录)
File file = new File("test.txt");
if (!file.exists()) {
file.createNewFile();
System.out.println("文件创建成功");
}
// 2. 获取文件属性
System.out.println("文件名:" + file.getName());
System.out.println("文件绝对路径:" + file.getAbsolutePath());
System.out.println("文件大小:" + file.length() + "字节");
System.out.println("最后修改时间:" + new Date(file.lastModified()));
System.out.println("是否为文件:" + file.isFile());
// 3. 创建多级目录
File dir = new File("file/demo/java");
if (!dir.exists()) {
dir.mkdirs(); // 一次性创建多级目录
System.out.println("多级目录创建成功");
}
// 4. 删除文件
// file.delete();
}
}
关键方法区别:
mkdir() 只能创建单级目录,上级目录不存在则创建失败;mkdirs() 可创建多级目录,开发优先使用。
5.6.3 递归遍历目录树(实战高频)
递归遍历目录是文件批量处理、文件检索、资源扫描的基础,核心逻辑:判断是否为目录,是目录则继续递归遍历子文件。
import java.io.File;
public class FileTreeDemo {
public static void main(String[] args) {
// 遍历当前项目根目录
File root = new File(System.getProperty("user.dir"));
printFileTree(root, 0);
}
/**
* 递归打印目录树
* @param file 当前文件/目录对象
* @param level 层级,用于格式化缩进
*/
public static void printFileTree(File file, int level) {
// 层级缩进展示
for (int i = 0; i < level; i++) {
System.out.print("│ ");
}
System.out.println("├─ " + file.getName());
// 如果是目录,递归遍历子文件
if (file.isDirectory()) {
File[] files = file.listFiles();
// 非空判断,避免空指针
if (files != null) {
for (File subFile : files) {
printFileTree(subFile, level + 1);
}
}
}
}
}
5.7 枚举类 Enum
5.7.1 枚举核心概念
JDK5 新增 枚举(enum) 类型,是一种特殊的类,默认直接继承 java.lang.Enum。
核心用途:用于定义固定不变的常量集合,替代传统静态常量。适用于订单状态、支付状态、季节、星期、性别、业务类型等固定场景。
优势知识点:相比普通静态常量,枚举安全性更高、可读性更强、可用于switch精准匹配、自带遍历方法、杜绝非法参数。
5.7.2 枚举基础定义与使用
// 定义订单状态枚举
enum OrderStatus {
// 固定常量,默认 public static final 修饰
PENDING, // 待支付
PAID, // 已支付
DELIVERED, // 已发货
COMPLETED, // 已完成
CANCELLED // 已取消
}
public class EnumDemo {
public static void main(String[] args) {
// 枚举遍历:values()获取所有枚举常量
for (OrderStatus status : OrderStatus.values()) {
System.out.println("订单状态:" + status);
}
// switch搭配枚举判断(业务高频、无枚举值报错)
OrderStatus currentStatus = OrderStatus.PAID;
switch (currentStatus) {
case PENDING:
System.out.println("订单待支付,请尽快付款");
break;
case PAID:
System.out.println("订单已支付,准备发货");
break;
case COMPLETED:
System.out.println("订单已完成");
break;
default:
System.out.println("订单状态异常");
}
}
}
底层知识点:枚举常量本质是枚举类的静态常量对象,每个常量都是当前枚举类的一个实例。
本章核心知识点总结
-
包装类实现基本类型与对象的转换,JDK9后推荐valueOf()创建对象,数值型包装类继承Number类实现统一转型;
-
自动装箱拆箱是编译器语法糖,装箱调用valueOf(),拆箱调用xxxValue(),需注意null拆箱空指针问题;
-
Integer等数值包装类缓存-128~127区间数据,数值比较必须用equals(),规避缓存坑点;
-
String不可变、性能低、线程安全;StringBuilder可变、单线程高性能;StringBuffer可变、多线程安全;
-
Date存储时间戳,SimpleDateFormat负责时间格式化与解析,Calendar实现灵活的日期加减与修改;
-
Math提供静态数学计算方法,适配常规运算;Random可灵活生成任意区间随机数,适配各类随机场景;
-
File类负责文件、目录的创建、删除、属性查询,结合递归可实现全盘目录遍历;
-
枚举用于定义固定业务常量,安全性、可读性远超普通静态常量,是业务状态管理首选。
更多推荐

所有评论(0)