# 2.7 我们的第一个Java程序
最后,让我们正式编一个程序(注释⑤)。它能打印出与当前运行的系统有关的资料,并利用了来自Java标准库的`System`对象的多种方法。注意这里引入了一种额外的注释样式:`//`。它表示到本行结束前的所有内容都是注释:
```
// Property.java
import java.util.*;
public class Property {
public static void main(String[] args) {
System.out.println(new Date());
Properties p = System.getProperties();
p.list(System.out);
System.out.println("--- Memory Usage:");
Runtime rt = Runtime.getRuntime();
System.out.println("Total Memory = "
+ rt.totalMemory()
+ " Free Memory = "
+ rt.freeMemory());
}
}
```
⑤:在某些编程环境里,程序会在屏幕上一切而过,甚至没机会看到结果。可将下面这段代码置于`main()`的末尾,用它暂停输出:
```
try {
Thread.currentThread().sleep(5 * 1000);
} catch(InterruptedException e) {}
}
```
它的作用是暂停输出5秒钟。这段代码涉及的一些概念要到本书后面才会讲到。所以目前不必深究,只知道它是让程序暂停的一个技巧便可。
在每个程序文件的开头,都必须放置一个`import`语句,导入那个文件的代码里要用到的所有额外的类。注意我们说它们是“额外”的,因为一个特殊的类库会自动导入每个Java文件:`java.lang`。启动您的Web浏览器,查看由Sun提供的用户文档(如果尚未从 `http://www.java.sun.com` 下载,或用其他方式安装了Java文档,请立即下载)。在`packages.html`文件里,可找到Java配套提供的所有类库名称。请选择其中的`java.lang`。在“Class Index”下面,可找到属于那个库的全部类的列表。由于`java.lang`默认进入每个Java代码文件,所以这些类在任何时候都可直接使用。在这个列表里,可发现`System`和`Runtime`,我们在`Property.java`里用到了它们。`java.lang`里没有列出`Date`类,所以必须导入另一个类库才能使用它。如果不清楚一个特定的类在哪个类库里,或者想检视所有的类,可在Java用户文档里选择“Class Hierarchy”(类分级结构)。在Web浏览器中,虽然要花不短的时间来建立这个结构,但可清楚找到与Java配套提供的每一个类。随后,可用浏览器的“查找”(Find)功能搜索关键字`Date`。经这样处理后,可发现我们的搜索目标以`java.util.Date`的形式列出。我们终于知道它位于`util`库里,所以必须导入 `java.util.*`;否则便不能使用`Date`。
观察`packages.html`文档最开头的部分(我已将其设为自己的默认起始页),请选择`java.lang`,再选`System`。这时可看到`System`类有几个字段。若选择`out`,就可知道它是一个`static PrintStream`对象。由于它是“静态”的,所以不需要我们创建任何东西。`out`对象肯定是3,所以只需直接用它即可。我们能对这个`out`对象做的事情由它的类型决定:`PrintStream`。`PrintStream`在说明文字中以一个超链接的形式列出,这一点做得非常方便。所以假若单击那个链接,就可看到能够为`PrintStream`调用的所有方法。方法的数量不少,本书后面会详细介绍。就目前来说,我们感兴趣的只有`println()`。它的意思是“把我给你的东西打印到控制台,并用一个新行结束”。所以在任何Java程序中,一旦要把某些内容打印到控制台,就可条件反射地写上`System.out.println("内容")`。
类名与文件是一样的。若象现在这样创建一个独立的程序,文件中的一个类必须与文件同名(如果没这样做,编译器会及时作出反应)。类里必须包含一个名为`main()`的方法,形式如下:
```
public static void main(String[] args) {
```
其中,关键字`public`意味着方法可由外部世界调用(第5章会详细解释)。`main()`的参数是包含了`String`对象的一个数组。`args`不会在本程序中用到,但需要在这个地方列出,因为它们保存了在命令行调用的参数。
程序的第一行非常有趣:
```
System.out.println(new Date());
```
请观察它的参数:创建`Date`对象唯一的目的就是将它的值发送给`println()`。一旦这个语句执行完毕,`Date`就不再需要。随之而来的“垃圾收集器”会发现这一情况,并在任何可能的时候将其回收。事实上,我们没太大的必要关心“清除”的细节。
第二行调用了`System.getProperties()`。若用Web浏览器查看联机用户文档,就可知道`getProperties()`是`System`类的一个`static`方法。由于它是“静态”的,所以不必创建任何对象便可调用该方法。无论是否存在该类的一个对象,`static`方法随时都可使用。调用`getProperties()`时,它会将系统属性作为`Properties`类的一个对象生成(注意`Properties`是“属性”的意思)。随后的的引用保存在一个名为`p`的`Properties`引用里。在第三行,大家可看到`Properties`对象有一个名为`list()`的方法,它将自己的全部内容都发给一个我们作为参数传递的`PrintStream`对象。
`main()` 的第四和第六行是典型的打印语句。注意为了打印多个`String`值,用加号(`+`)分隔它们即可。然而,也要在这里注意一些奇怪的事情。在`String`对象中使用时,加号并不代表真正的“相加”。处理字符串时,我们通常不必考虑`+`的任何特殊含义。但是,Java的`String`类要受一种名为“运算符重载”的机制的制约。也就是说,只有在随同`String`对象使用时,加号才会产生与其他任何地方不同的表现。对于字符串,它的意思是“连接这两个字符串”。
但事情到此并未结束。请观察下述语句:
```
System.out.println("Total Memory = "
+ rt.totalMemory()
+ " Free Memory = "
+ rt.freeMemory());
```
其中,`totalMemory()`和`freeMemory()`返回的是数值,并非`String`对象。如果将一个数值“加”到一个字符串身上,会发生什么情况呢?同我们一样,编译器也会意识到这个问题,并魔术般地调用一个方法,将那个数值(`int`,`float`等等)转换成字符串。经这样处理后,它们当然能利用加号“加”到一起。这种“自动类型转换”亦划入“运算符重载”处理的范畴。
许多Java著作都在热烈地辩论“运算符重载”(C++的一项特性)是否有用。目前就是反对它的一个好例子!然而,这最多只能算编译器(程序)的问题,而且只是对`String`对象而言。对于自己编写的任何源代码,都不可能使运算符“重载”。
通过为`Runtime`类调用`getRuntime()`方法,`main()`的第五行创建了一个`Runtime`对象。返回的则是指向一个`Runtime`对象的引用。而且,我们不必关心它是一个静态对象,还是由`new`命令创建的一个对象。这是由于我们不必为清除工作负责,可以大模大样地使用对象。正如显示的那样,`Runtime`可告诉我们与内存使用有关的信息。
- Java 编程思想
- 写在前面的话
- 引言
- 第1章 对象入门
- 1.1 抽象的进步
- 1.2 对象的接口
- 1.3 实现方案的隐藏
- 1.4 方案的重复使用
- 1.5 继承:重新使用接口
- 1.6 多态对象的互换使用
- 1.7 对象的创建和存在时间
- 1.8 异常控制:解决错误
- 1.9 多线程
- 1.10 永久性
- 1.11 Java和因特网
- 1.12 分析和设计
- 1.13 Java还是C++
- 第2章 一切都是对象
- 2.1 用引用操纵对象
- 2.2 所有对象都必须创建
- 2.3 绝对不要清除对象
- 2.4 新建数据类型:类
- 2.5 方法、参数和返回值
- 2.6 构建Java程序
- 2.7 我们的第一个Java程序
- 2.8 注释和嵌入文档
- 2.9 编码样式
- 2.10 总结
- 2.11 练习
- 第3章 控制程序流程
- 3.1 使用Java运算符
- 3.2 执行控制
- 3.3 总结
- 3.4 练习
- 第4章 初始化和清除
- 4.1 用构造器自动初始化
- 4.2 方法重载
- 4.3 清除:收尾和垃圾收集
- 4.4 成员初始化
- 4.5 数组初始化
- 4.6 总结
- 4.7 练习
- 第5章 隐藏实现过程
- 5.1 包:库单元
- 5.2 Java访问指示符
- 5.3 接口与实现
- 5.4 类访问
- 5.5 总结
- 5.6 练习
- 第6章 类复用
- 6.1 组合的语法
- 6.2 继承的语法
- 6.3 组合与继承的结合
- 6.4 到底选择组合还是继承
- 6.5 protected
- 6.6 累积开发
- 6.7 向上转换
- 6.8 final关键字
- 6.9 初始化和类装载
- 6.10 总结
- 6.11 练习
- 第7章 多态性
- 7.1 向上转换
- 7.2 深入理解
- 7.3 覆盖与重载
- 7.4 抽象类和方法
- 7.5 接口
- 7.6 内部类
- 7.7 构造器和多态性
- 7.8 通过继承进行设计
- 7.9 总结
- 7.10 练习
- 第8章 对象的容纳
- 8.1 数组
- 8.2 集合
- 8.3 枚举器(迭代器)
- 8.4 集合的类型
- 8.5 排序
- 8.6 通用集合库
- 8.7 新集合
- 8.8 总结
- 8.9 练习
- 第9章 异常差错控制
- 9.1 基本异常
- 9.2 异常的捕获
- 9.3 标准Java异常
- 9.4 创建自己的异常
- 9.5 异常的限制
- 9.6 用finally清除
- 9.7 构造器
- 9.8 异常匹配
- 9.9 总结
- 9.10 练习
- 第10章 Java IO系统
- 10.1 输入和输出
- 10.2 增添属性和有用的接口
- 10.3 本身的缺陷:RandomAccessFile
- 10.4 File类
- 10.5 IO流的典型应用
- 10.6 StreamTokenizer
- 10.7 Java 1.1的IO流
- 10.8 压缩
- 10.9 对象序列化
- 10.10 总结
- 10.11 练习
- 第11章 运行期类型识别
- 11.1 对RTTI的需要
- 11.2 RTTI语法
- 11.3 反射:运行期类信息
- 11.4 总结
- 11.5 练习
- 第12章 传递和返回对象
- 12.1 传递引用
- 12.2 制作本地副本
- 12.3 克隆的控制
- 12.4 只读类
- 12.5 总结
- 12.6 练习
- 第13章 创建窗口和程序片
- 13.1 为何要用AWT?
- 13.2 基本程序片
- 13.3 制作按钮
- 13.4 捕获事件
- 13.5 文本字段
- 13.6 文本区域
- 13.7 标签
- 13.8 复选框
- 13.9 单选钮
- 13.10 下拉列表
- 13.11 列表框
- 13.12 布局的控制
- 13.13 action的替代品
- 13.14 程序片的局限
- 13.15 视窗化应用
- 13.16 新型AWT
- 13.17 Java 1.1用户接口API
- 13.18 可视编程和Beans
- 13.19 Swing入门
- 13.20 总结
- 13.21 练习
- 第14章 多线程
- 14.1 反应灵敏的用户界面
- 14.2 共享有限的资源
- 14.3 堵塞
- 14.4 优先级
- 14.5 回顾runnable
- 14.6 总结
- 14.7 练习
- 第15章 网络编程
- 15.1 机器的标识
- 15.2 套接字
- 15.3 服务多个客户
- 15.4 数据报
- 15.5 一个Web应用
- 15.6 Java与CGI的沟通
- 15.7 用JDBC连接数据库
- 15.8 远程方法
- 15.9 总结
- 15.10 练习
- 第16章 设计模式
- 16.1 模式的概念
- 16.2 观察器模式
- 16.3 模拟垃圾回收站
- 16.4 改进设计
- 16.5 抽象的应用
- 16.6 多重分发
- 16.7 访问器模式
- 16.8 RTTI真的有害吗
- 16.9 总结
- 16.10 练习
- 第17章 项目
- 17.1 文字处理
- 17.2 方法查找工具
- 17.3 复杂性理论
- 17.4 总结
- 17.5 练习
- 附录A 使用非JAVA代码
- 附录B 对比C++和Java
- 附录C Java编程规则
- 附录D 性能
- 附录E 关于垃圾收集的一些话
- 附录F 推荐读物