一、字符串类

Java API(Application Programming Interface)是 Java 提供的一套预先定义的类和接口,用于简化开发人员的编程工作,涵盖了字符串处理、集合操作、IO 流、网络编程等众多领域。其中,字符串类是 Java 中最常用的 API 之一,主要包括StringStringBufferStringBuilder三个核心类,它们在字符串的创建、修改和操作中扮演着不同的角色。

1.String类的初始化

String类用于表示不可变的字符序列(一旦创建,字符串的内容就无法修改),其初始化主要有两种常见方式:

(1)直接赋值方式

通过字面量直接赋值,字符串会被加入字符串常量池(方法区中的一块内存区域,用于缓存字符串字面量,避免重复创建),实现复用。

// 直接赋值,s1指向常量池中的"Hello Java"
String s1 = "Hello Java";
// s2复用常量池中的"Hello Java",与s1指向同一对象
String s2 = "Hello Java";
System.out.println(s1 == s2); // 输出true(引用地址相同)

(2)通过 new 关键字创建

通过new String()构造方法创建的字符串对象,会在堆内存中新建对象,即使内容相同,也会创建新的实例(常量池若不存在该字面量,会先在常量池创建,再在堆中创建对象指向常量池的字面量)。

// 堆中创建新对象,s3指向堆地址,常量池同时存在"Hello Java"
String s3 = new String("Hello Java");
// 堆中创建另一个新对象,s4指向新的堆地址
String s4 = new String("Hello Java");
System.out.println(s3 == s4); // 输出false(引用地址不同)
System.out.println(s3.equals(s4)); // 输出true(内容相同)

(3)其他构造方法

String还提供了基于字符数组、字节数组等的构造方法(了解即可):

// 基于字符数组初始化
char[] chs = {'J', 'a', 'v', 'a'};
String s5 = new String(chs); // 结果为"Java"

// 基于字节数组初始化(指定编码)
byte[] bytes = "Java".getBytes(StandardCharsets.UTF_8);
String s6 = new String(bytes, StandardCharsets.UTF_8); // 结果为"Java"

2.String类的常见操作

String类提供了丰富的方法用于字符串的查询、比较、截取、替换等操作,以下是最常用的方法:

(1)字符串长度与空判断

  • int length():返回字符串的字符个数。
  • boolean isEmpty():判断字符串是否为空(长度为 0)。
String s = "Java API";
System.out.println(s.length()); // 输出7
System.out.println(s.isEmpty()); // 输出false

(2)字符与子串查询

  • char charAt(int index):获取指定索引位置的字符(索引从 0 开始)。
  • int indexOf(String str):返回子串第一次出现的索引,不存在则返回 - 1。
  • int lastIndexOf(String str):返回子串最后一次出现的索引。
String s = "Hello Java";
System.out.println(s.charAt(6)); // 输出'J'
System.out.println(s.indexOf("Java")); // 输出6
System.out.println(s.lastIndexOf("o")); // 输出4

(3)字符串比较

  • boolean equals(Object obj):比较字符串内容是否相同(区分大小写)。
  • boolean equalsIgnoreCase(String anotherString):忽略大小写比较内容。
  • int compareTo(String anotherString):按字典序比较(返回差值,0 表示相等)。
String s1 = "Java";
String s2 = "java";
System.out.println(s1.equals(s2)); // 输出false
System.out.println(s1.equalsIgnoreCase(s2)); // 输出true
System.out.println(s1.compareTo(s2)); // 输出-32('J'与'j'的ASCII差值)

(4)字符串截取与拆分

  • String substring(int beginIndex):从指定索引截取到字符串末尾。
  • String substring(int beginIndex, int endIndex):截取 [beginIndex, endIndex) 区间的子串(左闭右开)。
  • String[] split(String regex):按指定正则表达式拆分字符串为数组。
String s = "Hello,Java,API";
System.out.println(s.substring(6)); // 输出"Java,API"
System.out.println(s.substring(6, 10)); // 输出"Java"
String[] arr = s.split(","); // 结果为["Hello", "Java", "API"]

(5)字符串替换与去除空格

  • String replace(CharSequence target, CharSequence replacement):替换指定子串。
  • String replaceAll(String regex, String replacement):按正则表达式替换。
  • String trim():去除字符串首尾的空白字符(JDK11 + 提供strip(),支持全角空格)。
String s = "  Hello Java  ";
System.out.println(s.replace("Java", "API")); // 输出"  Hello API  "
System.out.println(s.trim()); // 输出"Hello Java"

(6)字符串转换

  • String toUpperCase():转换为大写。
  • String toLowerCase():转换为小写。
  • static String valueOf(Object obj):将任意类型转换为字符串(常用作字符串拼接)。
String s = "Java API";
System.out.println(s.toUpperCase()); // 输出"JAVA API"
System.out.println(String.valueOf(123)); // 输出"123"

3.StringBuffer类

StringBuffer线程安全的可变字符序列,用于频繁修改字符串的场景(如多线程环境下的字符串拼接),其对象的内容可以通过方法修改,不会创建新的对象。

(1)初始化

// 空构造,初始容量为16
StringBuffer sb1 = new StringBuffer();
// 指定初始字符串
StringBuffer sb2 = new StringBuffer("Java");
// 指定初始容量
StringBuffer sb3 = new StringBuffer(20);

(2)核心方法(支持链式调用)

  • append(任意类型):在字符串末尾追加内容。
  • insert(int offset, 任意类型):在指定位置插入内容。
  • delete(int start, int end):删除 [start, end) 区间的字符。
  • replace(int start, int end, String str):替换指定区间的字符。
  • reverse():反转字符串。
  • toString():转换为 String 类型。
StringBuffer sb = new StringBuffer("Hello");
sb.append(" Java") // 变为"Hello Java"
  .insert(5, ",") // 变为"Hello, Java"
  .reverse(); // 变为"avaJ ,olleH"
System.out.println(sb.toString()); // 输出最终结果
4.StringBuilder类

StringBuilder非线程安全的可变字符序列,功能与StringBuffer几乎完全一致,但去掉了方法的同步锁,因此性能更高,是单线程环境下修改字符串的首选。

StringBuffer用法完全一致:

StringBuilder sb = new StringBuilder("Java");
sb.append(" API")
  .insert(4, ",");
System.out.println(sb.toString()); // 输出"Java, API"

 与 StringBuffer 的区别:

特性 StringBuffer StringBuilder
线程安全 线程安全(同步) 非线程安全(非同步)
性能 较低(同步开销) 较高(无同步开销)
适用场景 多线程环境 单线程环境

二、System类与Runtime类

在 Java API 中,System类和Runtime类是与系统环境、虚拟机运行状态密切相关的核心类,二者均提供了访问和操作 JVM 及底层系统资源的能力,但设计定位和使用方式有所不同。

1.System类

java.lang.System是一个最终类(final),且构造方法被私有化(无法实例化),所有方法和属性均为静态的,主要用于访问系统级资源(如标准输入输出、系统属性、环境变量)、执行系统级操作(如数组拷贝、垃圾回收、退出程序)等。

System类提供了三个常用的静态成员变量,用于处理标准输入、输出和错误流:

  • public static final InputStream in:标准输入流(通常对应键盘输入)。
  • public static final PrintStream out:标准输出流(通常对应控制台输出)。
  • public static final PrintStream err:标准错误流(用于输出错误信息,同样指向控制台,但输出优先级更高)。
// 标准输出
System.out.println("Hello, System!");
// 标准错误输出
System.err.println("This is an error message!");

(1)系统属性与环境变量

  • static Properties getProperties():获取当前 JVM 的系统属性集合(如 Java 版本、操作系统名称、用户目录等)。
  • static String getProperty(String key):根据键获取指定的系统属性值。
  • static String getenv(String name):获取指定的系统环境变量(如 PATH、JAVA_HOME)。
// 获取Java版本
String javaVersion = System.getProperty("java.version");
System.out.println("Java版本:" + javaVersion);

// 获取操作系统名称
String osName = System.getProperty("os.name");
System.out.println("操作系统:" + osName);

// 获取环境变量JAVA_HOME
String javaHome = System.getenv("JAVA_HOME");
System.out.println("JAVA_HOME:" + javaHome);

(2)数组拷贝

static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):高效的数组拷贝方法(native 方法,底层由 C/C++ 实现,性能优于手动循环拷贝)。

  • src:源数组;srcPos:源数组起始拷贝位置;
  • dest:目标数组;destPos:目标数组起始粘贴位置;
  • length:拷贝的元素个数。
int[] src = {1, 2, 3, 4, 5};
int[] dest = new int[5];
// 将src中从索引0开始的3个元素,拷贝到dest的索引1开始的位置
System.arraycopy(src, 0, dest, 1, 3);
// 输出:[0, 1, 2, 3, 0]
System.out.println(Arrays.toString(dest));

(3)系统时间与计时

static long currentTimeMillis():返回当前时间与 1970 年 1 月 1 日 00:00:00 GMT 的时间差(毫秒数),常用于计时或生成时间戳。

public class Timetest {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();//循环开始时的当前时间
        int sum = 0;
        for (int i = 0; i < 100000000; i++) {
            sum += i;
        }
        long end = System.currentTimeMillis();//循环结束时的当前时间
        System.out.println("循环时间:" + (end - start) + "ms");
    }
}

发现循环时间为1毫秒,不对劲。问了AI,发现原因是:

Java 虚拟机的 JIT 编译器会对热点代码(频繁执行的代码)进行优化,比如循环展开、常量折叠、死代码消除等。对于你这个循环,sum += i 的计算结果没有被使用,JIT 可能会直接优化掉整个循环,导致输出的时间接近 0ms,无法反映真实的执行时间。采用static long nanoTime()。

static long nanoTime():返回 JVM 的高精度时间戳(纳秒级),适用于短时间间隔的精确测量(不受系统时间修改的影响)。

public class Timetest {
    public static void main(String[] args) {
        // 计算代码执行耗时
        long start = System.nanoTime();
        for (int i = 0; i < 100000; i++) {
            // 模拟耗时操作
        }
        long end = System.nanoTime();
        System.out.println("执行耗时:" + (end - start) + "纳秒");
    }
}

(4)垃圾回收与退出程序

static void gc():建议 JVM 执行垃圾回收(注意:仅为建议,JVM 是否执行由垃圾回收器决定)。

class Person {
    public void finalize() {
        System.out.println("对象将作为垃圾回收...");
    }
}

public class Test_gc {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person();
        //下面将变量设置为null
        p1 = null;
        p2 = null;
        // 手动触发垃圾回收
        System.gc();
    }
}

2.Runtime类

java.lang.Runtime类用于表示当前 JVM 的运行时环境,每个 JVM 进程仅有一个Runtime实例(单例模式),通过它可以访问 JVM 的内存信息、执行外部进程、管理线程等,更侧重于对 JVM 自身运行状态的控制和查询。

Runtime类的构造方法被私有化,通过 ** 静态方法getRuntime()** 获取唯一实例:

Runtime runtime = Runtime.getRuntime();

(1)JVM 内存信息查询

用于获取 JVM 的内存分配、使用情况,是调优 JVM 的重要依据:

  • long totalMemory():返回 JVM 当前的总内存(堆内存),单位为字节(初始为 - Xms 指定的大小,可动态扩展至maxMemory())。
  • long maxMemory():返回 JVM 可使用的最大内存(对应 - Xmx 指定的大小)。
  • long freeMemory():返回 JVM 当前的空闲内存。
Runtime runtime = Runtime.getRuntime();
System.out.println("JVM总内存:" + runtime.totalMemory() / 1024 / 1024 + "MB");
System.out.println("JVM最大内存:" + runtime.maxMemory() / 1024 / 1024 + "MB");
System.out.println("JVM空闲内存:" + runtime.freeMemory() / 1024 / 1024 + "MB");

(2)执行外部进程

通过exec()方法可以启动操作系统的外部程序(如 exe、sh 脚本),实现 Java 程序与外部进程的交互:

  • Process exec(String command):执行指定的系统命令,返回Process对象用于控制外部进程。
  • Process exec(String[] cmdarray):执行命令数组(更安全,避免命令注入)。
Runtime runtime = Runtime.getRuntime();
// 执行Windows的notepad.exe(记事本程序)
try {
    Process process = runtime.exec("notepad.exe");
    // 等待外部进程执行完毕
    int exitCode = process.waitFor();
    System.out.println("外部进程退出码:" + exitCode);
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

(3)JVM 相关操作

  • void gc():与System.gc()功能一致,建议 JVM 执行垃圾回收(底层调用的是同一个实现)。
  • void addShutdownHook(Thread hook):添加 JVM 关闭钩子线程(当 JVM 正常退出时,该线程会被执行,常用于资源释放)。
  • void removeShutdownHook(Thread hook):移除已添加的关闭钩子线程。
Runtime runtime = Runtime.getRuntime();
// 添加关闭钩子:JVM退出时执行资源释放
runtime.addShutdownHook(new Thread(() -> {
    System.out.println("JVM即将退出,释放资源中...");
    // 模拟释放数据库连接、文件流等
}));

// 触发JVM退出
System.exit(0);

(4)其他方法(了解即可)

  • int availableProcessors():返回当前系统的可用处理器核心数(用于判断并发能力)。
  • void halt(int status):强制终止 JVM 进程(与exit()不同,halt()不会执行关闭钩子和最终化方法,属于暴力退出)。
Runtime runtime = Runtime.getRuntime();
System.out.println("可用处理器核心数:" + runtime.availableProcessors());

三、Math类与Random类

在 Java API 中,Math类和Random类是处理数值计算随机数生成的核心工具类,广泛应用于数学运算、游戏开发、数据模拟等场景。Math类提供了丰富的静态数学方法,而Random类专注于生成各种类型的随机数,二者相辅相成,共同满足程序中的数值处理需求。

1.Math类

java.lang.Math是一个最终类(final),构造方法被私有化(无法实例化),所有方法和常量均为静态的。它封装了常用的数学运算功能,如算术运算、三角函数、指数对数、取整、最值计算等,底层多基于原生代码实现,保证了运算效率。

Math类定义了两个常用的数学常量,精度为双精度浮点型(double):

  • public static final double PI:圆周率(π),约等于 3.141592653589793。
  • public static final double E:自然常数(e),约等于 2.718281828459045。
// 计算圆的面积(面积=πr²)
double r = 5.0;
double area = Math.PI * Math.pow(r, 2);
System.out.println("圆的面积:" + area); // 输出约78.53981633974483

(1)算术运算:绝对值、最值、幂运算

  • static int abs(int a)/long abs(long a)/float abs(float a)/double abs(double a):返回参数的绝对值(支持多种数值类型)。
  • static int max(int a, int b)/double max(double a, double b):返回两个数的最大值(同理min()返回最小值)。
  • static double pow(double a, double b):返回ab次幂(a^b)。
  • static double sqrt(double a):返回a的平方根(仅支持非负数,负数返回NaN)。
  • static double cbrt(double a):返回a的立方根(支持负数)。
System.out.println(Math.abs(-10)); // 输出10
System.out.println(Math.max(3.5, 2.8)); // 输出3.5
System.out.println(Math.pow(2, 3)); // 输出8.0(2的3次幂)
System.out.println(Math.sqrt(16)); // 输出4.0

(2)取整运算:四舍五入、向上 / 向下取整

Math类提供了多种取整方式,适用于不同的数值处理场景:

  • static long round(double a):将数值四舍五入为最接近的长整型(double参数)。
  • static int round(float a):四舍五入为整型(float参数)。
  • static double ceil(double a):向上取整(返回大于等于参数的最小整数)。
  • static double floor(double a):向下取整(返回小于等于参数的最大整数)。
  • static double rint(double a):返回最接近参数的整数(若距离相等,返回偶数)。
System.out.println(Math.round(3.6)); // 输出4
System.out.println(Math.ceil(3.2)); // 输出4.0
System.out.println(Math.floor(3.9)); // 输出3.0
System.out.println(Math.rint(2.5)); // 输出2.0(与2.5距离相等,返回偶数)

(3)三角函数与指数对数

适用于科学计算场景,所有参数均以弧度为单位(可通过toRadians()将角度转换为弧度):

  • static double sin(double a)/cos(double a)/tan(double a):正弦、余弦、正切函数。
  • static double asin(double a)/acos(double a)/atan(double a):反正弦、反余弦、反正切函数。
  • static double log(double a):自然对数(ln a)。
  • static double log10(double a):以 10 为底的对数。
  • static double exp(double a):自然常数 e 的 a 次幂(e^a)。
  • static double toRadians(double angdeg):将角度转换为弧度。
  • static double toDegrees(double angrad):将弧度转换为角度。
// 计算30度的正弦值(30度=π/6弧度)
double sin30 = Math.sin(Math.toRadians(30));
System.out.println("30度的正弦值:" + sin30); // 输出约0.5
System.out.println(Math.log(Math.E)); // 输出1.0(ln e=1)

(4)随机数(已过时,推荐使用 Random 类)

Math类提供了一个简单的随机数方法,但功能单一且随机性较弱:

  • static double random():返回一个[0.0, 1.0)区间的双精度随机数。
// 生成1-100的随机整数
int randomNum = (int) (Math.random() * 100 + 1);
System.out.println(randomNum);

2.Random类

java.util.Random类是 Java 提供的随机数生成器,用于生成伪随机数(基于种子值的算法生成,若种子相同,生成的随机数序列也相同)。它支持生成多种类型的随机数(intlongfloatdoubleboolean),功能比Math.random()更丰富、灵活。

Random类有两种构造方式,核心区别在于种子的来源

无参构造:使用系统当前时间的纳秒数作为默认种子,每次运行生成的随机数序列不同。

Random random = new Random();

有参构造:指定固定种子(long类型),种子相同则生成的随机数序列完全一致(可用于复现测试场景)。

// 固定种子,每次运行生成的随机数序列相同
Random random = new Random(100);

(1)生成基本类型随机数

  • int nextInt():生成一个int范围内的随机整数(-2^31 ~ 2^31-1)。
  • int nextInt(int bound):生成[0, bound)区间的随机整数(bound必须为正数,否则抛异常)。
  • long nextLong():生成long范围内的随机长整数。
  • float nextFloat():生成[0.0, 1.0)区间的随机浮点数。
  • double nextDouble():生成[0.0, 1.0)区间的随机双精度数(与Math.random()等价)。
  • boolean nextBoolean():生成随机的布尔值(truefalse)。
Random random = new Random();
System.out.println(random.nextInt(100)); // 生成0-99的随机整数
System.out.println(random.nextBoolean()); // 生成true或false
System.out.println(random.nextDouble()); // 生成0.0-1.0的随机数
(2)生成指定范围的随机数

通过简单的数学运算,可生成任意区间的随机数:

  • 生成[a, b]区间的整数:random.nextInt(b - a + 1) + a
  • 生成[a, b)区间的浮点数:a + random.nextDouble() * (b - a)
Random random = new Random();
// 生成10-20的随机整数(包含10和20)
int num1 = random.nextInt(11) + 10;
// 生成0.5-1.5的随机浮点数
double num2 = 0.5 + random.nextDouble() * 1.0;
System.out.println(num1);
System.out.println(num2);

(3)生成字节数组随机数

  • void nextBytes(byte[] bytes):将随机生成的字节填充到指定的字节数组中。
byte[] bytes = new byte[5];
Random random = new Random();
random.nextBytes(bytes);
System.out.println(Arrays.toString(bytes)); // 输出随机字节数组

(4)生成高斯分布随机数

  • double nextGaussian():生成服从标准正态分布的随机数(均值为 0,标准差为 1),适用于统计模拟场景。
Random random = new Random();
// 生成10个标准正态分布的随机数
for (int i = 0; i < 10; i++) {
    System.out.println(random.nextGaussian());
}

四、日期时间类

java.time 包(JSR 310),提供了一套全新的日期时间 API,包括InstantLocalDateLocalTimeLocalDateTimePeriodDuration等核心类。这些类采用不可变设计,线程安全且 API 更直观,成为处理日期时间的首选。

1.Instant类

Instant类表示时间戳,对应 UTC(世界协调时间)的一个瞬时点,精确到纳秒级别,相当于 Unix 时间戳(从 1970 年 1 月 1 日 00:00:00 UTC 开始的毫秒数)的拓展。它主要用于记录事件的时间戳、跨时区的时间统一表示。

(1)获取当前时间戳

  • static Instant now():获取当前系统的瞬时时间戳。
Instant now = Instant.now();
System.out.println(now);

(2)时间戳的构建与转换

  • static Instant ofEpochMilli(long epochMilli):通过毫秒数构建Instant(对应 Unix 时间戳)。
  • long toEpochMilli():将Instant转换为从 1970-01-01 00:00:00 UTC 开始的毫秒数。
  • static Instant parse(CharSequence text):解析 ISO-8601 格式的字符串为Instant(如2025-12-21T08:15:30Z
// 通过毫秒数构建
Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());
// 转换为毫秒数
long milli = instant.toEpochMilli();
// 解析字符串
Instant parsed = Instant.parse("2025-12-21T08:15:30Z");

(3)时间戳的加减与比较

  • Instant plusSeconds(long seconds)/plusMillis(long millis)/plusNanos(long nanos):添加秒、毫秒、纳秒。
  • Instant minusSeconds(long seconds):减少指定时间单位。
  • int compareTo(Instant other):比较两个Instant的先后(返回负数表示当前对象更早,0 表示相等,正数表示更晚)。
Instant now = Instant.now();
Instant later = now.plusHours(1); // 1小时后
Instant earlier = now.minusMinutes(30); // 30分钟前
System.out.println(later.compareTo(now)); // 输出1(later更晚)

2.LocalData类

LocalDate类表示本地日期(年 - 月 - 日),不包含时间和时区信息,仅关注日期本身(如 2025-12-21)。

(1)获取当前日期与构建日期

  • static LocalDate now():获取当前系统的本地日期。
  • static LocalDate of(int year, int month, int dayOfMonth):通过年、月、日构建LocalDate(月份支持数字 1-12 或Month枚举)。
  • static LocalDate parse(CharSequence text):解析 ISO-8601 格式的字符串(如2025-12-21)为LocalDate
// 当前日期
LocalDate today = LocalDate.now();
// 构建指定日期
LocalDate birthday = LocalDate.of(2000, 1, 1);
// 解析字符串
LocalDate parsed = LocalDate.parse("2025-12-21");

(2)日期的属性获取

  • int getYear():获取年份。
  • Month getMonth():获取月份(返回Month枚举,如DECEMBER)。
  • int getDayOfMonth():获取日期中的日。
  • DayOfWeek getDayOfWeek():获取星期几(返回DayOfWeek枚举,如SUNDAY)。
  • int lengthOfMonth():获取当月的天数。
  • boolean isLeapYear():判断是否为闰年。
LocalDate date = LocalDate.of(2025, 12, 21);
System.out.println(date.getYear()); // 2025
System.out.println(date.getDayOfWeek()); // SUNDAY
System.out.println(date.isLeapYear()); // false

(3)日期的加减与调整

  • LocalDate plusYears(long years)/plusMonths(long months)/plusDays(long days):添加年、月、日。
  • LocalDate minusWeeks(long weeks):减少指定周数。
  • LocalDate withYear(int year):修改年份(返回新对象,原对象不变)。
  • LocalDate with(TemporalAdjuster adjuster):使用时间调整器(如获取当月第一天、下一个周一)。
LocalDate date = LocalDate.now();
LocalDate nextYear = date.plusYears(1); // 明年今日
LocalDate firstDayOfMonth = date.with(TemporalAdjusters.firstDayOfMonth()); // 当月第一天
LocalDate nextMonday = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); // 下一个周一

(4)日期比较

  • boolean isBefore(ChronoLocalDate other):判断当前日期是否在指定日期之前。
  • boolean isAfter(ChronoLocalDate other):判断当前日期是否在指定日期之后。
  • int compareTo(ChronoLocalDate other):比较日期先后。
LocalDate date1 = LocalDate.of(2025, 12, 20);
LocalDate date2 = LocalDate.of(2025, 12, 21);
System.out.println(date1.isBefore(date2)); // true

3.LocalTime类与LocalDataTime类

(1)LocalTime 类

LocalTime类表示本地时间(时:分: 秒。纳秒),不包含日期和时区信息,仅关注时间本身(如 14:30:45.123)。

 常用方法
  • static LocalTime now():获取当前系统的本地时间。
  • static LocalTime of(int hour, int minute, int second):通过时、分、秒构建LocalTime
  • LocalTime plusHours(long hours)/minusMinutes(long minutes):时间的加减。
  • int getHour()/int getMinute():获取时、分等属性。
  • boolean isBefore(LocalTime other):时间比较。
// 当前时间
LocalTime now = LocalTime.now();
// 构建指定时间
LocalTime time = LocalTime.of(14, 30, 0);
// 1小时后
LocalTime later = time.plusHours(1);
System.out.println(later); // 15:30:00

(2)LocalDateTime 类

LocalDateTime类是LocalDateLocalTime的组合,表示本地日期时间(年 - 月 - 日 时:分: 秒。纳秒),不包含时区信息。

获取与构建
  • static LocalDateTime now():获取当前系统的本地日期时间。
  • static LocalDateTime of(LocalDate date, LocalTime time):通过LocalDateLocalTime构建。
  • static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute):直接指定年、月、日、时、分构建。
  • static LocalDateTime parse(CharSequence text):解析 ISO-8601 格式的字符串(如2025-12-21T14:30:45)。
// 当前日期时间
LocalDateTime now = LocalDateTime.now();
// 通过日期和时间构建
LocalDate date = LocalDate.of(2025, 12, 21);
LocalTime time = LocalTime.of(14, 30);
LocalDateTime dateTime = LocalDateTime.of(date, time);
// 解析字符串
LocalDateTime parsed = LocalDateTime.parse("2025-12-21T14:30:45");
时区转换

LocalDateTime本身无时区,但可通过ZonedDateTime转换为带时区的时间:

// 转换为东八区时间
ZonedDateTime zoned = dateTime.atZone(ZoneId.of("Asia/Shanghai"));

(3)核心对比

包含信息 适用场景
LocalTime 时:分: 秒。纳秒 仅需时间的场景(如发车时间)
LocalDateTime 年 - 月 - 日 时:分: 秒。纳秒 本地具体时间点(如订单支付时间)

4.Period和Duration类

(1)Period 类

Period表示基于日期的时间间隔(年、月、日),适用于计算两个LocalDate之间的间隔。

常用方法
  • static Period between(LocalDate startDate, LocalDate endDate):计算两个日期之间的间隔。
  • int getYears()/int getMonths()/int getDays():获取间隔的年、月、日。
  • Period plusYears(long years):增加间隔的年数。
  • Period multipliedBy(int n):将间隔乘以指定倍数。
LocalDate start = LocalDate.of(2020, 1, 1);
LocalDate end = LocalDate.of(2025, 12, 21);
// 计算间隔
Period period = Period.between(start, end);
System.out.println(period.getYears()); // 5
System.out.println(period.getMonths()); // 11
System.out.println(period.getDays()); // 20

(2)Duration 类

Duration表示基于时间的时间间隔(秒、纳秒),适用于计算两个InstantLocalTimeLocalDateTime之间的间隔,支持天、时、分、秒、毫秒、纳秒的换算。

常用方法
  • static Duration between(Temporal start, Temporal end):计算两个时间对象之间的间隔。
  • long toDays()/long toHours()/long toMinutes():将间隔转换为天、时、分。
  • long getSeconds():获取间隔的秒数。
  • Duration plusMinutes(long minutes):增加间隔的分钟数。
LocalTime start = LocalTime.of(10, 0, 0);
LocalTime end = LocalTime.of(14, 30, 0);
// 计算时间间隔
Duration duration = Duration.between(start, end);
System.out.println(duration.toHours()); // 4
System.out.println(duration.toMinutes()); // 270(4小时30分钟)

// 计算Instant的间隔
Instant instant1 = Instant.now();
Instant instant2 = instant1.plusSeconds(120);
Duration dur = Duration.between(instant1, instant2);
System.out.println(dur.getSeconds()); // 120

(3)核心对比

间隔单位 适用的时间类型
Period 年、月、日 LocalDate
Duration 秒、纳秒(可换算天 / 时 / 分) Instant、LocalTime、LocalDateTime

五、包装类

在 Java 中,包装类(Wrapper Class) 是为 8 种基本数据类型提供的引用类型封装,位于java.lang包下。Java 是面向对象的语言,但基本数据类型不具备对象的特性(如无法调用方法、不能作为泛型参数、无法参与多态等),包装类的出现弥补了这一缺陷,实现了基本数据类型与对象的相互转换,同时提供了丰富的数值处理方法。

Java 为 8 种基本数据类型分别提供了对应的包装类,可分为两类:

数值型包装类(继承自Number类)

基本数据类型 对应的包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double

非数值型包装类

基本数据类型 对应的包装类
char Character
boolean Boolean

基本数据类型与包装类的转换是包装类最常用的功能,包括装箱拆箱两种操作。装箱:基本数据类型 → 包装类对象(引用数据类型);拆箱:包装类对象(引用数据类型) → 基本数据类型。

自动装箱:编译器自动将基本数据类型转换为对应的包装类对象,无需手动调用包装类的valueOf()方法。

自动拆箱:编译器自动将包装类对象转换为对应的基本数据类型,无需手动调用包装类的xxxValue()方法(如intValue())。

public class Test03 {
    public static void main(String[] args) {
        int a = 20;
        Integer in =a;//自动装箱
        System.out.println(in);
        int l =in;//自动拆箱
        System.out.println(l);
    }
}

注意:如果包装类对象为null,自动拆箱会抛出NullPointerException(这段代码中in有值,所以不会出现此问题)。

手动装箱:通过Integer类的构造方法,将基本类型int20封装为Integer包装类对象。

手动拆箱:调用Integer类的intValue()方法,将Integer包装类对象转换为对应的int基本数据类型。

public class Test04 {
    public static void main(String[] args) {
        Integer num = new Integer(20);//手动装箱
        int sum = num.intValue() + 10;//手动拆箱
        System.out.println("将Integeer类型的值转为int类型后与10相加的结果:" + sum);
        System.out.println("返回表示10的Integer实例为:" + Integer.valueOf(10));
        int w = Integer.parseInt("20") + 32;
        System.out.println("将字符串\"20\"转换为int类型后与32相加的结果:" + w);
    }
}

六、正则表达式

正则表达式(Regular Expression)是一种用于匹配、查找、替换字符串的强大工具,它通过预定义的元字符普通字符组成的模式,实现对字符串的灵活匹配。Java 中通过java.util.regex包下的Pattern类和Matcher类提供正则表达式的核心支持,同时String类也内置了便捷的正则处理方法,让字符串的正则操作更加简洁。

1.元字符

元字符是正则表达式的核心,分为基本元字符限定符分组与断言等类型,用于描述字符的匹配规则。

元字符 含义 示例
. 匹配任意单个字符(除了换行符\n a.b匹配a1baab
\d 匹配任意数字(0-9),等价于[0-9] \d{3}匹配123
\D 匹配任意非数字字符,等价于[^0-9] \D匹配a@
\w 匹配任意单词字符(字母、数字、下划线),等价于[a-zA-Z0-9_] \w+匹配java123
\W 匹配任意非单词字符,等价于[^a-zA-Z0-9_] \W匹配@#
\s 匹配任意空白字符(空格、制表符\t、换行符\n等) \s匹配空格、\t
\S 匹配任意非空白字符 \S匹配a1
[] 字符集,匹配括号内的任意一个字符(支持范围,如[a-z]表示小写字母) [abc]匹配ab
[^] 否定字符集,匹配不在括号内的任意一个字符 [^abc]匹配d1
` ` 或运算,匹配左边或右边的表达式
* 匹配前面的字符 0 次或多次 a*匹配""aaa
+ 匹配前面的字符 1 次或多次 a+匹配aaa
? 匹配前面的字符 0 次或 1 次(可选) a?匹配""a
{n} 匹配前面的字符恰好 n 次 a{3}匹配aaa
{n,} 匹配前面的字符至少 n 次 a{2,}匹配aaaaa
{n,m} 匹配前面的字符至少 n 次,最多 m 次 a{2,3}匹配aaaaa
^ 匹配字符串的开头 ^java匹配java123
$ 匹配字符串的结尾 java$匹配123java
\b 匹配单词边界(单词与非单词的分隔处) \bjava\b匹配java(不匹配javac
\B 匹配非单词边界 \Bjava\B匹配javac中的java
() 分组,将括号内的表达式作为一个整体,可结合限定符使用
\n 反向引用,引用第 n 个分组的匹配结果(n 从 1 开始)

2.Pattern类和Matcher类

java.util.regex.Pattern(模式类)和java.util.regex.Matcher(匹配器类)是 Java 处理正则表达式的核心类,Pattern用于编译正则表达式(生成模式对象),Matcher用于对字符串进行匹配操作,二者配合使用可实现复杂的正则处理。

(1)Pattern 类

Pattern 类是不可变的线程安全的,它的核心作用是编译正则表达式(将字符串形式的正则表达式转换为高效的内部表示),避免重复编译提升性能。

常用方法
  • static Pattern compile(String regex):编译正则表达式,返回 Pattern 对象(核心方法)。
  • static Pattern compile(String regex, int flags):编译正则表达式并指定匹配标志(如Pattern.CASE_INSENSITIVE表示忽略大小写)。
  • Matcher matcher(CharSequence input):创建一个 Matcher 对象,用于对输入字符串进行匹配。
  • static boolean matches(String regex, CharSequence input):静态方法,直接匹配整个字符串(等价于编译后调用matcher.matches())。
  • String[] split(CharSequence input):按正则表达式拆分字符串(与 String 的 split 方法类似)。

(2)Matcher 类

Matcher 类是非线程安全的,它通过 Pattern 对象创建,用于对字符串进行匹配、查找、替换等操作,提供了丰富的匹配状态和方法。

常用方法
  • 匹配整个字符串boolean matches():判断整个输入字符串是否完全匹配正则表达式。
  • 查找子串boolean find():在输入字符串中查找下一个匹配的子串(多次调用可遍历所有匹配项)。
  • 获取匹配结果
    • String group():返回当前匹配的子串;
    • int start():返回当前匹配子串的起始索引;
    • int end():返回当前匹配子串的结束索引(不包含)。
  • 替换操作
    • String replaceAll(String replacement):替换所有匹配的子串;
    • String replaceFirst(String replacement):替换第一个匹配的子串。

匹配字符串中的所有数字:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexDemo {
    public static void main(String[] args) {
        // 1. 定义正则表达式和输入字符串
        String regex = "\\d+"; // 匹配一个或多个数字
        String input = "Java123Regex456Pattern789";
        
        // 2. 编译正则表达式
        Pattern pattern = Pattern.compile(regex);
        
        // 3. 创建Matcher对象
        Matcher matcher = pattern.matcher(input);
        
        // 4. 查找所有匹配的子串
        while (matcher.find()) {
            System.out.println("匹配到的子串:" + matcher.group());
            System.out.println("起始索引:" + matcher.start() + ",结束索引:" + matcher.end());
        }
    }
}

3.String类对正则表达式的支持

为了简化开发,String类内置了多个直接支持正则表达式的方法,这些方法底层其实是调用了PatternMatcher类的功能,但使用起来更便捷。

(1)匹配操作:matches(String regex)

  • 作用:判断整个字符串是否完全匹配指定的正则表达式(返回 boolean)。
  • 注意:与 Matcher 的matches()方法一致,需匹配整个字符串,而非子串。

判断是否为合法的手机号(以 1 开头,11 位数字):

String phone = "13812345678";
boolean isPhone = phone.matches("^1[3-9]\\d{9}$");
System.out.println(isPhone);

(2)拆分操作:split(String regex)

  • 作用:按正则表达式拆分字符串,返回字符串数组(支持指定拆分次数)。
  • 重载方法:split(String regex, int limit):limit 指定拆分的最大次数。

按任意空白字符拆分字符串:

String str = "Java  Regex  Pattern";
String[] arr = str.split("\\s+"); // 按一个或多个空白字符拆分
System.out.println(Arrays.toString(arr)); // 输出[Java, Regex, Pattern]

(3)替换操作

  • replaceAll(String regex, String replacement):替换所有匹配的子串;
  • replaceFirst(String regex, String replacement):替换第一个匹配的子串。

替换字符串中的所有数字为*:

String str = "Java123Regex456";
String newStr = str.replaceAll("\\d+", "*");
System.out.println(newStr); // 输出Java*Regex*
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐