1. 概述

本教程将快速介绍 java.lang.System 类的核心功能与特性。作为 Java 基础库的关键成员,System 类提供了与 JVM 交互的底层能力。

2. IO 操作

System 类最核心的功能之一是提供标准 I/O 流的访问。它暴露了三个关键字段:

  • out:标准输出流
  • err:标准错误流
  • in:标准输入流

2.1 System.out

System.out 指向标准输出流,封装为 PrintStream 类型,常用于控制台输出:

System.out.print("这是一行内联消息");

进阶用法是通过 System.setOut 重定向输出目标:

// 重定向到文本文件
System.setOut(new PrintStream("output.txt"));

2.2 System.err

System.errSystem.out 类似,都是 PrintStream 实例,但专用于错误输出:

System.err.print("这是一行错误消息");

⚠️ 控制台通常会对错误流和输出流进行差异化渲染(如不同颜色)。更多细节可查阅 PrintStream 文档

2.3 System.in

System.in 暴露标准输入流(InputStream),用于读取控制台输入。基础用法稍显繁琐:

public String readUsername(int length) throws IOException {
    byte[] name = new byte[length];
    System.in.read(name, 0, length); // 默认从控制台读取
    return new String(name);
}

踩坑提醒:用户输入的多余字节会残留在流中,等待下次读取!更优雅的方案是使用 BufferedReader

public String readUsername() throws IOException {
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(System.in));
    return reader.readLine();
}

⚠️ 切勿关闭标准输入流!关闭后程序生命周期内将无法再次读取。进阶用法可通过 System.setIn 重定向输入源。

3. 实用工具方法

System 类提供大量实用方法,涵盖以下场景:

  • 控制台访问
  • 数组复制
  • 时间观测
  • 程序退出
  • 运行时属性访问
  • 环境变量访问
  • 垃圾回收管理

3.1 访问控制台

Java 1.6 引入了比直接使用 System.out/in 更强大的控制台交互方式:

public String readUsername() {
    Console console = System.console();          
    return console == null ? null :     
        console.readLine("%s", "请输入用户名: ");          
}

⚠️ 必须检查空值!根据 JVM 启动方式(如 IDE 运行),console() 可能返回 null。更多用法见 Console 文档

3.2 数组复制

System.arraycopy 是 C 风格的数组复制方法,支持全量或部分复制:

int[] a = {34, 22, 44, 2, 55, 3};
int[] b = new int[a.length];

// 全量复制
System.arraycopy(a, 0, b, 0, a.length);
assertArrayEquals(a, b);

// 部分复制:从 a[1] 开始复制 2 个元素到 b[3]
System.arraycopy(a, 1, b, 3, 2); 
assertArrayEquals(new int[] {0, 0, 0, 22, 44, 0}, b);

❌ 可能抛出异常:

  • NullPointerException:任一数组为 null
  • IndexOutOfBoundsException:越界访问
  • ArrayStoreException:类型不匹配

3.3 时间观测

System 提供两个时间相关方法:

  1. currentTimeMillis:返回 Unix 纪元(1970-01-01 00:00:00 UTC)至今的毫秒数 ```java public long nowPlusOneHour() { return System.currentTimeMillis() + 3600 * 1000L; }

public String nowPrettyPrinted() { return new Date(System.currentTimeMillis()).toString(); }


2. `nanoTime`:返回 JVM 启动后的纳秒级时间,适合测量时间间隔
```java
long startTime = System.nanoTime();
// 执行代码
long endTime = System.nanoTime();

assertTrue(endTime - startTime < 10000);

⚠️ 避免直接比较时间值!由于数值溢出风险,应使用差值比较(如 endTime - startTime < threshold)。

3.4 程序退出

System.exit 可强制终止当前程序,需指定退出码:

if (error) {
    System.exit(1); // 非零表示异常退出
} else {
    System.exit(0); // 零表示正常退出
}

⚠️ 慎用此方法!在 Web 服务器等环境中调用可能导致整个应用崩溃。

3.5 访问运行时属性

通过 System.getProperty 访问 JVM 属性,支持动态管理:

// 获取属性
public String getJavaVMVendor() {
    return System.getProperty("java.vm.vendor");
}
    
// 设置属性
System.setProperty("abckey", "abcvaluefoo");
assertEquals("abcvaluefoo", System.getProperty("abckey"));

// 清除属性
System.clearProperty("abckey");
assertNull(System.getProperty("abckey"));

✅ 支持默认值:

System.clearProperty("dbHost");
String host = System.getProperty("dbHost", "db.host.com");
assertEquals("db.host.com", host);

通过 System.getProperties() 获取所有属性:

Properties properties = System.getProperties();
properties.clear(); // 清空所有属性(危险操作!)

3.6 访问环境变量

System.getenv 提供只读的环境变量访问:

public String getPath() {
    return System.getenv("PATH");
}

3.7 垃圾回收管理

System 提供两个垃圾回收相关方法(慎用):

  1. System.runFinalization():建议 JVM 执行 finalize() 方法
  2. System.gc():建议 JVM 执行垃圾回收

⚠️ 不保证立即执行!仅作为优化建议,典型场景如桌面应用最小化时触发:

public void windowStateChanged(WindowEvent event) {
    if (event == WindowEvent.WINDOW_DEACTIVATED) {
        System.gc(); // 触发垃圾回收(不保证执行)
    }
}

更多细节见 Java finalize 指南

4. 总结

本文介绍了 System 类的核心字段与方法。完整 API 可查阅 官方文档,所有示例代码见 GitHub 仓库


原始标题:Quick Guide to java.lang.System