1. Java 编译器
顺便说一句,你会多次听到,Java 相比其他语言最无可争辩的优势——就是跨平台性。这到底是什么?我们从头讲起。
事实是,计算机只能执行最简单的指令。
对狗来说,有“靠近”、“握爪”等口令,狗听到后会做出相应动作。对计算机而言,起这种作用的是数字:每条指令都被编码为某个数字(也称为机器码)。
把程序写成一串数字非常困难,因此人们发明了编程语言和编译器。这种语言一方面便于人理解,另一方面也便于编译器处理。编译器是一种特殊的程序,它把用编程语言编写的程序文本翻译成一组机器码。
通常程序员会先用编程语言写好程序,然后运行编译器,编译器会基于程序员写的源代码文件生成一个机器码文件——最终(已编译)的程序。
- 用 C++ 编写的程序
-
编译器
- 由机器 码构成的程序
最终得到的程序可以直接在计算机上运行。这种方式的缺点是,生成的程序代码与处理器和操作系统强相关。为 Windows 编译的程序无法在搭载 Android 的手机上运行。
如果你编写的是Android 程序,那么在Windows 操作系统上它无法启动!
而Java 采用了更具创新性的做法。
- 用 Java 编写的程序
-
Java‑编译器
- 由特殊代码(字节码)构成的程序
-
Java 虚拟机
- 由机器 码构成的程序
Java 编译器不会把所有类编译成一个由机器码组成的程序。相反,它会把每个类分别编译,而且不是编译成机器码,而是编译成一种特殊的中间代码(字节码)。在程序启动时才会编译为机器码。
那么在程序启动时是谁把它编译成机器码呢?
为此有一个名为 JVM(Java Virtual Machine,Java 虚拟机)的特殊程序。先启动它,然后再启动由字节码组成的程序。而 JVM 会在执行所需程序之前,将其编译为机器码。
如果你的处理器很强,支持更大的机器指令集,那么在“第二次编译”时,会根据你的处理器和操作系统生成机器码。这也是为什么 Java 有时会比 C++ 更快,后者直接被编译为机器码,只能利用处理器中最常见的那部分指令。
2. 编译时的典型错误
目前速度和优化对我们还不那么重要,而更重要的是,编译器会检查你的程序是否有错误。它会检查代码的正确性,哪怕发现一个小错误,也不会让它继续往下走。
错误示例:
你试图把一个数字赋给只能存放文本的变量。
String userName = 42; // 哎呀!这样不行。
编译器会立即报类型不匹配的错误:Cannot implicitly convert type 'int' to 'string'。
另一个示例——在命令 println 里打错了字:
System.out.printline("你好!"); // 方法名写错了
编译器会说:“没有这个方法——检查语法!”
如何阅读错误信息?
大多数编译器都会提示代码中出错的位置,有时甚至会给出修复建议。别害怕错误:每一个错误都是通往顿悟、打败你内心“Boss”的一步。
3. 注释
试想:你写了一个复杂的程序。一切运行正常,你——是个天才!但一个月后你再打开那段代码……什么都看不懂。这里几行代码,那里一个奇怪的变量。脑子里只有:“这肯定不是我写的!”这时,注释就能救你。
注释就像课本页边的批注,或冰箱门上的便条(“啤酒。别喝。留到明天!”)。编译器会忽略它们,而人类——恰恰相反。注释可以用来解释代码意图、标注重要细节,甚至可以“关闭”部分程序而不必删除它们。
重要:没有任何编译器会读取你的注释,它们会被完全忽略!
单行注释
在 Java 中有两种注释——单行和多行。单行注释以双斜杠 // 开始,并一直持续到行尾。// 之后的所有内容都被视为注释,并会被编译器完全忽略。
示例:
System.out.println("你好,世界!"); // 这会在屏幕上输出问候语
这里的 // 这会在屏幕上输出问候语——就是注释。如果一行代码的用途不太明显,就这样写下来!
再一个示例:
int x = 42; // 程序员的年龄值
单行注释也可以单独占一行:
// 初始化用户名变量
String userName = "瓦夏";
几乎就像剧本中的台词:注释解释了“为什么”和“为了什么”。
多行注释
如果要说的内容很多,像讲一个故事一样?可以使用多行注释,它以 /* 开始,以 */ 结束。这两个符号之间的所有内容都会被编译器忽略,即使它跨越多行。
示例:
/*
这里我们在屏幕上输出用户名。
如果没有名字,就写上“访客”。
*/
System.out.println("请输入你的姓名:");
或者这样:
int age = 18; /* 初始年龄值
适用于新用户 */
注意:多行注释不能相互嵌套。别试图比编译器更聪明——这不会奏效。
示意:
| 类型 | 语法 | 示例 |
|---|---|---|
| 单行 | |
|
| 多行 | |
|
4. 生活中的示例
“禁用”一行代码:
有时你想暂时不执行某个代码片段。此时注释就派上用场了:
// System.out.println("暂时不需要的文本");
这一行还在,但编译器“看不见”它。
TODO 和 FIXME 标记
程序员也是人,有时需要提醒自己:这段代码还没写完,或者这里有个 bug。常见的写法是:
// TODO: 添加对空输入的检查
// FIXME: 这个函数对总和的计算不正确
许多编辑器和 IDE 甚至会高亮这些词!
程序员的段子
// 我对这段代码不负责。有人强迫我违背本意写的。
// 亲爱的,我_来自未来!请原谅我写下这段代码。
// 如果我再看到这种东西,我就不得不开始带武器上班了。
// 如果这个条件某天真的成立,请拨打 xxx-xxx-xxx 通知我,重酬。
// 亲爱的软件工程师:
//
// 当你“优化”完这个子程序
// 并意识到这么做是多大的错误时,
// 请把下面的计数器加一,作为对下一个人的警告:
//
// hours_spent_here = 42
// 当我开始写它时,只有上帝和我明白我在做什么。
// 现在只剩上帝了
// 有时我觉得编译器忽略了我所有的注释
// 我把我所有的代码、所有的工作献给我的妻子达琳,
// 当这玩意儿上线时,她将不得不养活我、我们的三个孩子和狗。
没错,注释也可以很有趣。毕竟它们是活生生的人写的。
GO TO FULL VERSION