☕ 第六章 Java API
📄 一句话概括

System 是一个不能 new 的系统工具箱:成员全是 static,类名直接点——out 打印、currentTimeMillis 秒表、exit 停机、arraycopy 搬数组。3.6/3.7 的 static 知识在这里第一次大规模实战。

💡 先修课

3.6 代码块 与 3.7 static关键字(static 静态成员的规矩)、2.7 数组(arraycopy 的主场)、第六章 Java API/6.2 字符串类(循环 + 拼接的坑,本节用秒表实测)。


1. System 是什么?——一个"开不了门"的类

System.out.println("Hello");   // 用了一个月,今天正式认识

System 类的构造方法是私有的(private),new 不出来——全世界就一份,所有成员都是 static,用类名直接点调用:

System.out     // 字段:标准输出流
System.err     // 字段:标准错误流(红色字)
System.in      // 字段:标准输入流(键盘,后面配 Scanner)
📝 为什么不让 new?

工具类不需要多个实例——一份就够。构造私有 + 成员全 static 是工具类的标准设计套路(Math、Arrays、Integer.parseInt 全是同一套路)。3.6/3.7 学 static 时说"工具箱方法挂在类上",这就是实物。

2. currentTimeMillis():系统秒表

long now = System.currentTimeMillis();
System.out.println(now);   // 例如 1789476245123

返回从 1970-1-1 00:00:00 到现在的总毫秒数(计算机的"纪元起点",1.4 讲运行机制时提过)。这个数本身没啥用,差值才是精华——夹逼测耗时:

long start = System.currentTimeMillis();     // 起表
for (int i = 0; i < 100000; i++) {
    s = s + i;                               // 循环狂拼字符串
}
long end = System.currentTimeMillis();       // 停表
System.out.println("耗时:" + (end - start) + " 毫秒");

这个套路到处都用:测算法快慢、接口响应时间,全是它。

3. exit(int status):总闸停机

System.exit(0);   // 0 = 正常退出;非 0 = 异常退出

JVM 直接停机——比 return 狠得多:return 只是结束当前方法,exit 是整个程序原地断电。

⚠️ exit 和 finally 有仇

5.3 学过"finally 两路必跑,System.exit 除外"——就是它。一按停机,finally、后面的代码统统不跑。急着退出时才用,别当 return 用。

4. arraycopy():数组搬运工(五参数)

int[] src  = {10, 20, 30, 40, 50};
int[] dest = new int[5];
System.arraycopy(src, 1, dest, 0, 3);
// dest = {20, 30, 40, 0, 0}

五参数口诀:从哪 · 起步 · 到哪 · 放哪 · 搬几个

参数 含义 示例值
src 源数组(从哪复制) src
srcPos 从源的下标几开始 1
dest 目标数组(到哪) dest
destPos 放到目标的下标几 0
length 一共搬几个 3

比 2.7 手写 for 循环复制快(底层是内存级拷贝),Arrays.copyOf 的底层也是它——工具箱里藏着的"基础设施"。

5. gc():跟 JVM 打个招呼(了解)

System.gc() 建议 JVM 收垃圾。只是"建议"——什么时候真收 JVM 说了算。新手期记住一句:Java 的内存回收是自动的,不用你操心,知道有这号人物即可。

6. 动手环节(IDEA06 · Demo03)

  1. 写 Demo03,先打印 System.currentTimeMillis(),跑一遍看看这个大数。
  2. 夹逼秒表:循环 10 万次 s += i 拼字符串,打印耗时。成功标准:控制台给出一个毫秒数(几百到几千不等)。
  3. 30 秒实验 ①:把循环改成 for (int i = 0; i < 100000; i++) sb.append(i);(StringBuilder 语法下节讲,先照抄)→ 对比耗时,差距通常几十倍——6.2 埋的钩子用数据收网。
  4. 30 秒实验 ②:try-finally 里写 System.exit(0); → finally 里的打印没出现,亲眼看"finaly 拦不住停机"。
  5. 30 秒实验 ③:arraycopy 按"从哪·起步·到哪·放哪·搬几个"口诀改五组参数,每次打印 dest 验证理解。

7. 常见误区

⚠️ 四大误区
  1. 想 new System() → 构造私有,编不过。工具类全是类名直接点。
  2. 拿 currentTimeMillis 的返回值当日期看 → 它是 1970 起的总毫秒数,不是"现在几点"(要日期用日期类,后面学)。
  3. exit 当 return 用 → return 结束方法,exit 结束整个程序,还能跳过 finally。
  4. arraycopy 五参数背顺序 → 别死背,记口诀"从哪·起步·到哪·放哪·搬几个"。

8. 本节小结

要点 内容
身份 构造私有的工具类,成员全 static,类名直接点
out / err / in 标准(输出/错误/输入)流
currentTimeMillis 1970 起的毫秒数;夹逼秒表测耗时
exit 总闸停机,finally 都拦不住
arraycopy 五参数数组搬运工,底层基础设施
gc 建议 JVM 收垃圾(了解)

9. 可折叠自测题

❓ Q1:为什么 System 不能 new?我们平时怎么用它的成员?

构造方法被 private 修饰,外部无法创建实例。它的成员全是 static(静态成员属于类不属于对象),所以直接 System.out、System.currentTimeMillis() 用类名调用——3.7 static 的标准应用。

❓ Q2:夹逼秒表测耗时的三行套路是什么?

起表 long start = System.currentTimeMillis(); → 跑被测代码 → 停表 long end = ...,end - start 就是毫秒耗时。本质:两次取当前毫秒值求差。

❓ Q3:`System.arraycopy(arr, 2, brr, 1, 4)` 每个参数什么意思?

从 arr 的下标 2 开始,复制到 brr 的下标 1 开始的位置,一共搬 4 个元素。口诀:从哪(arr)·起步(2)·到哪(brr)·放哪(1)·搬几个(4)。

❓ Q4:try 里调 System.exit(0),finally 还跑吗?和 return 拦不住 finally 矛盾吗?

不跑。不矛盾——return 只是"结束方法但程序还活着",JVM 有空跑 finally;exit 是"程序直接断电",没有"之后"可言。5.3 讲的"finally 两路必跑"本来就注明了 exit 例外。

❓ Q5(毕业题):用秒表实测循环 10 万次字符串拼接的耗时,并解释为什么慢。
long start = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 100000; i++) s += i;
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + " 毫秒");

慢的原因:String 不可变(6.2),每次 += 都要造新对象再拷贝旧内容——10 万次就是 10 万批新对象。解法是 6.3 之后的 StringBuilder,可变容器攒完再一次性变 String。


10. 下一步学什么


相关笔记