深入理解 Java 中的字符串、包装类与日期处理

在 Java 编程中,字符串操作、基本类型包装以及日期时间处理是日常开发中高频出现的场景。掌握这些知识点不仅能提升代码效率,更能避免一些隐藏的坑。本文将系统讲解 String 字符串、可变字符串、八大包装类及日期处理的核心知识与实践技巧。

一、字符串:不可变的字符序列

String 类是 Java 中最常用的类之一,它的不可变性是理解其特性的关键。

1. 核心特性解析

  • 不可继承:String 被final修饰,无法被其他类继承。
  • 不可变对象:字符串一旦创建,其内部字符序列就不可修改。任何修改操作(如拼接、替换)都会生成新的 String 对象。
  • 两种创建方式
    // 字面量方式:创建于字符串常量池,相同内容会复用
    String s1 = "hello";
    // new方式:创建于堆内存,每次new都会生成新对象
    String s2 = new String("hello");
    System.out.println(s1 == s2); // 输出false(地址不同)
    System.out.println(s1.equals(s2)); // 输出true(内容相同)
    

2. 常用方法实战

String 类提供了丰富的方法用于字符串操作,以下是开发中最常用的 API:

方法分类关键方法功能说明
基础信息length()返回字符串长度
charAt(int index)获取指定索引的字符(索引从 0 开始)
查找操作indexOf(String str)查找子串首次出现的索引,不存在返回 - 1
lastIndexOf(String str)查找子串最后出现的索引
截取拼接substring(int begin)从 begin 索引截取到末尾
substring(int begin, int end)截取 [begin, end) 区间的子串
concat(String str)拼接字符串(等价于+,但效率更高)
修改转换replace(CharSequence old, CharSequence new)替换子串
split(String regex)按正则分割为字符串数组
toUpperCase()/toLowerCase()转换大小写
toCharArray()转为字符数组
类型转换valueOf(任意类型)静态方法,将其他类型转为字符串

示例代码

public class StringDemo {
    public static void main(String[] args) {
        String str = "Java Programming";
        
        // 基础操作
        System.out.println("长度:" + str.length()); // 18
        System.out.println("第5个字符:" + str.charAt(4)); // 空格
        
        // 查找与截取
        int index = str.indexOf("Program");
        System.out.println("Program起始索引:" + index); // 5
        System.out.println("截取子串:" + str.substring(5, 12)); // Program
        
        // 替换与分割
        String replaced = str.replace("Programming", "Coding");
        System.out.println("替换后:" + replaced); // Java Coding
        String[] parts = str.split(" ");
        System.out.println("分割结果:" + parts[0] + "|" + parts[1]); // Java|Programming
    }
}
  1. toCharArray()是 String 类的方法,作用是将字符串转换为字符数组(char[])。例如:

    String str = "hello";
    char[] arr = str.toCharArray(); // arr 结果为 {'h','e','l','l','o'}
    
  2. String.valueOf(char[])是 String 类的静态方法,作用是将字符数组(char[])转换为字符串(String),正好与 toCharArray() 相反。例如:

    char[] arr = {'h','i'};
    String str = String.valueOf(arr); // str 结果为 "hi"

二、可变字符串:StringBuilder 与 StringBuffer

当需要频繁修改字符串时,使用 String 会产生大量临时对象,导致性能问题。此时应选择可变字符串类

1. 两者的异同点

  • 共同点
    • 继承自AbstractStringBuilder,内部通过动态数组存储字符
    • 提供append()insert()delete()等修改方法,支持原地修改
  • 核心区别
    • StringBuffer:线程安全(方法加了synchronized锁),性能较低
    • StringBuilder:非线程安全,性能更高(单线程首选)

2. 常用方法与性能对比

核心方法

  • append(任意类型):末尾追加内容(最常用)
  • insert(int offset, 任意类型):指定位置插入
  • delete(int start, int end):删除 [start, end) 区间内容
  • reverse():反转字符串
  • toString():转为 String 类型

性能测试

public class StringPerformance {
    public static void main(String[] args) {
        int loop = 100000; // 十万次拼接
        
        // String拼接(效率极低)
        long start1 = System.currentTimeMillis();
        String s = "";
        for (int i = 0; i < loop; i++) {
            s += i;
        }
        long end1 = System.currentTimeMillis();
        System.out.println("String耗时:" + (end1 - start1) + "ms"); // 约3000ms
        
        // StringBuilder拼接(效率极高)
        long start2 = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < loop; i++) {
            sb.append(i);
        }
        long end2 = System.currentTimeMillis();
        System.out.println("StringBuilder耗时:" + (end2 - start2) + "ms"); // 约5ms
    }
}

结论:字符串修改频繁时,优先使用StringBuilder(单线程)或StringBuffer(多线程)。

三、包装类:基本类型的对象化封装

Java 是面向对象语言,但 8 种基本数据类型不是对象。包装类的出现正是为了将基本类型封装为对象,满足泛型、集合等场景的需求。

1. 八大包装类对应关系

基本数据类型包装类父类特殊说明
byteByteNumber-
shortShortNumber-
intIntegerNumber最常用,缓存 - 128~127 区间对象
longLongNumber-
floatFloatNumber-
doubleDoubleNumber-
charCharacterObject无父类 Number
booleanBooleanObject无父类 Number

2. 核心功能与自动装箱拆箱

  • 类型转换

    • 字符串转基本类型:Integer.parseInt("123")Double.parseDouble("3.14")
    • 基本类型转包装类:Integer.valueOf(123)(推荐,利用缓存)
    • 包装类转基本类型:Integer.intValue()
  • 自动装箱与拆箱(JDK5+)

    // 自动装箱:int -> Integer
    Integer a = 100; // 等价于 Integer a = Integer.valueOf(100);
    
    // 自动拆箱:Integer -> int
    int b = a; // 等价于 int b = a.intValue();
    
  • 缓存机制:Integer 对-128~127区间的值做了缓存,多次创建该区间的对象会复用:

    Integer x = 127;
    Integer y = 127;
    System.out.println(x == y); // true(复用缓存对象)
    
    Integer m = 128;
    Integer n = 128;
    System.out.println(m == n); // false(超出缓存范围,新建对象)

四、日期时间处理:从传统 API 到新特性

日期时间处理是开发中的难点,Java 提供了多套 API,其中 Java 8 的新 API 是目前的最佳选择。

1. 传统日期类(不推荐)

  • java.util.Date:表示特定瞬间,精度到毫秒,但多数方法已过时。
  • SimpleDateFormat:用于日期格式化与解析,但线程不安全。

2. Java 8 新日期 API(推荐)

Java 8 引入的java.time包解决了传统 API 的线程安全、设计混乱等问题,核心类包括:

  • LocalDate:日期(年 / 月 / 日)
  • LocalTime:时间(时 / 分 / 秒)
  • LocalDateTime:日期 + 时间
  • DateTimeFormatter:线程安全的格式化工具

核心优势

  • 不可变对象,线程安全
  • 方法链编程,操作简洁
  • 清晰区分日期、时间、带时区的时间

示例代码

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class NewDateDemo {
    public static void main(String[] args) {
        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前时间:" + now); // 2025-10-21T15:30:00.123
        
        // 格式化(线程安全)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm");
        String formatted = now.format(formatter);
        System.out.println("格式化后:" + formatted); // 2025年10月21日 15:30
        
        // 日期计算
        LocalDateTime tomorrow = now.plusDays(1); // 明天
        LocalDateTime lastMonth = now.minusMonths(1); // 上个月
        System.out.println("明天同一时间:" + tomorrow.format(formatter));
        
        // 解析字符串
        LocalDateTime parsed = LocalDateTime.parse("2023年01月01日 08:00", formatter);
        System.out.println("解析后的月份:" + parsed.getMonthValue()); // 1
    }
}

总结

  1. 字符串选择:少量操作选String,频繁修改选StringBuilder(单线程)或StringBuffer(多线程)。
  2. 包装类注意:利用自动装箱拆箱简化代码,但需注意null拆箱的空指针风险和缓存机制的影响。
  3. 日期处理:彻底抛弃DateSimpleDateFormat,全面使用 Java 8 的java.time包,兼顾安全性与易用性。

掌握这些基础组件的特性与最佳实践,能显著提升代码质量与开发效率,避免常见的性能问题和 bug。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值