Java基础全套教程(五)—— 常用类精讲

前面章节我们掌握了Java数组、多维数据存储、基础算法等核心内容,具备了基础代码编写能力。本章将聚焦Java高频核心常用类,这类类库是JDK原生提供的基础工具,贯穿所有Java项目开发、笔试面试,是日常编码使用率最高的核心内容。

本章将系统讲解包装类、字符串体系类、时间处理类、数学工具类、随机数类、文件操作类、枚举类,搭配全新原创案例、底层原理、开发陷阱与实战场景,帮大家彻底吃透Java基础常用类,告别只会调用不会原理的编程短板。

本章学习目标

  1. 掌握八大基本数据类型对应包装类的映射关系、核心作用与底层原理;

  2. 精通自动装箱、自动拆箱机制,掌握包装类缓存机制与面试高频坑点;

  3. 深度区分String、StringBuilder、StringBuffer的特性、性能差异与使用场景;

  4. 熟练掌握Date、SimpleDateFormat、Calendar时间类的使用与时间格式化、计算逻辑;

  5. 掌握Math、Random工具类的常用方法,实现数学计算、随机数生成等场景;

  6. 熟练使用File类操作文件与目录,掌握递归遍历目录树的实战写法;

  7. 理解枚举类的底层本质、使用场景,掌握枚举常量的基础用法。


5.1 基本数据类型包装类

5.1.1 包装类核心概念

Java是面向对象编程语言,但八大基本数据类型(byte、short、int、long、float、double、char、boolean)不属于对象,没有属性和方法,无法参与对象类型操作(如存入Object数组、集合存储、泛型使用等)。

为了解决基本类型不具备对象特性的问题,JDK为每一种基本数据类型,提供了对应的包装类(Wrapper Class),核心作用是将基本数据类型封装为对象,让基本类型可以完全适配面向对象的所有操作场景。

补充核心知识点

  1. 所有包装类均位于 java.lang 包,无需手动导包,开箱即用;

  2. 所有包装类都是不可变类,对象创建后,内部数值无法修改;

  3. JDK9 及以上版本废弃了所有包装类的构造方法,强制推荐静态方法创建对象;

  4. 包装类是集合、泛型、对象传参的必备基础,项目中无法脱离包装类开发。

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() 静态方法,效率更高、支持缓存、更安全。

包装类四大核心使用场景

  1. 基本类型与包装对象互转;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
    }
}

核心陷阱知识点

  1. 纯常量拼接:编译期优化,直接合并,无性能损耗;

  2. 含变量拼接:运行期创建新对象,循环中使用会造成严重性能问题;

  3. 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日期计算核心类。

核心底层知识点

  1. Calendar 是抽象类,无法直接 new,通过静态方法获取实例或 new 子类 GregorianCalendar;

  2. 月份取值范围 0~11:0代表1月,11代表12月,使用必须+1修正;

  3. 周日为一周的第一天,和国内习惯不同。

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("订单状态异常");
        }
    }
}

底层知识点:枚举常量本质是枚举类的静态常量对象,每个常量都是当前枚举类的一个实例。


本章核心知识点总结

  1. 包装类实现基本类型与对象的转换,JDK9后推荐valueOf()创建对象,数值型包装类继承Number类实现统一转型;

  2. 自动装箱拆箱是编译器语法糖,装箱调用valueOf(),拆箱调用xxxValue(),需注意null拆箱空指针问题;

  3. Integer等数值包装类缓存-128~127区间数据,数值比较必须用equals(),规避缓存坑点;

  4. String不可变、性能低、线程安全;StringBuilder可变、单线程高性能;StringBuffer可变、多线程安全;

  5. Date存储时间戳,SimpleDateFormat负责时间格式化与解析,Calendar实现灵活的日期加减与修改;

  6. Math提供静态数学计算方法,适配常规运算;Random可灵活生成任意区间随机数,适配各类随机场景;

  7. File类负责文件、目录的创建、删除、属性查询,结合递归可实现全盘目录遍历;

  8. 枚举用于定义固定业务常量,安全性、可读性远超普通静态常量,是业务状态管理首选。

更多推荐