1.用句柄操作对象
拥有一个句柄,并不表示必须有一个对象同它连接。创建一个句柄时,记住无
论如何都进行初始化:
String s = "asdf";
这里采用的是一种特殊类型:字串可用加引号的文字初始化。通常,必须为对象使用一种更通用的初始化类型。
2.所有对象都必须创建
创建句柄时,我们希望它同一个新对象连接。通常用new 关键字达到这一目的。
String s = new String("asdf");
2.1 保存到什么地方
程序运行时,我们最好对数据保存到什么地方做到心中有数。特别要注意的是内存的分配。
- 1)寄存器——处理器内部
寄存器是根据需要由编译器分配。我们对此没有直接的控制权。 - 2)栈——RAM
创建程序时,Java 编译器必须准确地知道栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java 数据要保存在栈里——特别是对象句柄,但Java 对象并不放到其中。 - 3)堆——RAM
保存了Java 对象。编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间! - 4)静态存储——RAM
程序运行期间,静态存储的数据将随时等候调用。可用static 关键字指出一个对象的特定元素是静态的。但Java 对象本身永远都不会置入静态存储空间。 - 5)常数存储
常数值通常直接置于程序代码内部。 - 6)非RAM 存储
若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于固定对象,对象保存在磁盘中。即使程序中止运行,它们仍可保持自己的状态不变。对于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体中。一旦需要,甚至能将它们恢复成普通的、基于RAM 的对象。
2.2 特殊情况:基本类型(primitive type)
之所以要特别对待,是由于用new 创建对象(特别是小的、简单的变量)并不是非常有效,因为new 将对象置于“堆”里。对于这些类型,Java 采纳了与C 和C++相同的方法。也就是说,不是用new 创建变量,而是创建一个并非句柄的“自动”变量。这个变量容纳了具体的值,并置于栈中,能够更高效地存取。
四种整型:byte short int long
两种浮点类型:float double
一种用于表示Unicode编码的字符单元的字符类型:char
表示真值:boolean
Java 决定了每种主要类型的大小。就象在大多数语言里那样,这些大小并不随着机器结构的变化而变化。这种大小的不可更改正是Java 程序具有很强移植能力的原因之一。
数值类型全都是有符号(正负号)的,所以不必费劲寻找没有符号的类型。
主数据类型也拥有自己的“封装器”(wrapper)类。这意味着假如想让堆内一个非主要对象表示那个主类型,就要使用对应的封装器。
用于进行高精度的计算:BigInteger 和BigDecimal。尽管它们大致可以划分为“封装器”类型,但两者都没有对应的“主类型”。
BigInteger 支持任意精度的整数。也就是说,我们可精确表示任意大小的整数值,同时在运算过程中不会丢失任何信息。
BigDecimal 支持任意精度的定点数字。
2.3 Java的数组
Java 的一项主要设计目标就是安全性。所以在C 和C++里困扰程序员的许多问题都未在Java 里重复。一个Java 可以保证被初始化,而且不可在它的范围之外访问。由于系统自动进行范围检查,所以必然要付出一些代价:针对每个数组,以及在运行期间对索引的校验,都会造成少量的内存开销。但由此换回的是更高的安全性,以及更高的工作效率。为此付出少许代价是值得的。
创建对象数组时,实际创建的是一个句柄数组。而且每个句柄都会自动初始化成一个特殊值,并带有自己的关键字:null(空)。一旦Java 看到null,就知道该句柄并未指向一个对象。正式使用前,必须为每个句柄都分配一个对象。若试图使用依然为null 的一个句柄,就会在运行期报告问题。因此,典型的数组错误在Java 里就得到了避免。
也可以创建基本类型数组。同样地,编译器能够担保对它的初始化,因为会将那个数组的内存划分成零。
3.绝对不要清除对象
3.1 基本类型的作用域
大多数程序设计语言都提供了“作用域”(Scope)的概念。对于在作用域里定义的名字,作用域同时决定了它的“可见性”以及“存在时间”。在C,C++和Java 里,作用域是由花括号的位置决定的。
3.2 对象的作用域
Java 对象不具备与基本类型一样的存在时间。用new 关键字创建一个Java 对象的时候,它会超出作用域的范围之外。
{
String s = new String("a string");
} /* 作用域的终点 */
句柄s 会在作用域的终点处消失。然而,s 指向的String 对象依然占据着内存空间。
Java 有一个特别的“垃圾收集器”,它会查找用new 创建的所有对象,并辨别其中哪些不再被引用。随后,它会自动释放由那些闲置对象占据的内存,以便能由新对象使用。这意味着我们根本不必操心内存的回收问题。
4.新建数据类型:类
4.1 字段和方法
若某个基本数据类型属于一个类成员,那么即使不明确(显式)进行初始化,也可以保证它们获得一个默认值。
然而,这种保证却并不适用于“局部”变量——那些变量并非一个类的字段。
5.方法、自变量和返回值
Java 的“方法”决定了一个对象能够接收的消息。
int x = a.f();
调用一个方法的行动通常叫作“向对象发送一条消息”。在上面的例子中,消息是f(),而对象是a。
面向对象的程序设计通常简单地归纳为“向对象发送消息”。
5.1 自变量列表
自变量列表规定了我们传送给方法的是什么信息。
6.构建Java程序
6.1 名字的可见性
为了给一个库生成明确的名字,采用了与Internet域名类似的名字。事实上,Java 的设计者鼓励程序员反转使用自己的Internet 域名,因为它们肯定是独一无二的。由于我的域名是BruceEckel.com,所以我的实用工具库就可命名为com.bruceeckel.utility.foibles。反转了域名后,可将点号想象成子目录。
Java 的这种特殊机制意味着所有文件都自动存在于自己的命名空间里。而且一个文件里的每个类都自动获得一个独一无二的标识符(当然,一个文件里的类名必须是唯一的)。
6.2 使用其他组件
用import 关键字准确告诉Java 编译器我们希望的类是什么。import 的作用是指示编译器导入一个“包”——或者说一个“类库”(在其他语言里,可将“库”想象成一系列函数、数据以及类的集合。但请记住,Java 的所有代码都必须写入一个类中)。
大多数时候,我们直接采用来自标准Java 库的组件(部件)即可,它们是与编译器配套提供的。使用这些组件时,没有必要关心冗长的保留域名。
6.3 static关键字
通常,我们创建类时会指出那个类的对象的外观与行为。除非用new 创建那个类的一个对象,否则实际上并未得到任何东西。只有执行了new 后,才会正式生成数据存储空间,并可使用相应的方法。
但在两种特殊的情形下,上述方法并不堪用。
一种情形是只想用一个存储区域来保存一个特定的数据——无论要创建多少个对象,甚至根本不创建对象。
另一种情形是我们需要一个特殊的方法,它没有与这个类的任何对象关联。也就是说,即使没有创建对象,也需要一个能调用的方法。
为满足这两方面的要求,可使用static(静态)关键字。
尽管是“静态”的,但只要应用于一个数据成员,就会明确改变数据的创建方式。
对方法来说,static 一项重要的用途就是帮助我们在不必创建对象的前提下调用那个方法。正如以后会看到的那样,这一点是至关重要的——特别是在定义程序运行入口方法main()的时候。
7.我们的第一个Java程序
一个特殊的类库会自动导入每个Java 文件:java.lang。
8.注释和嵌入文档
8.1 注释文档
若文档与代码分离,那么每次改变代码后都要改变文档,这无疑会变成相当麻烦的一件事情。解决的方法看起来似乎很简单:将代码同文档“链接”起来。为达到这个目的,最简单的方法是将所有内容都置于同一个文件。
用于提取注释的工具叫作javadoc。它采用了部分来自Java 编译器的技术,查找我们置入程序的特殊注释标记。它不仅提取由这些标记指示的信息,也将毗邻注释的类名或方法名提取出来。这样一来,我们就可用最轻的工作量,生成十分专业的程序文档。
8.2 具体语法
所有javadoc 命令都只能出现于“/”注释中。但和平常一样,注释结束于一个“/”。主要通过两种方式来使用javadoc:嵌入的HTML,或使用“文档标记”。其中,“文档标记”(Doc tags)是一些以“@”开头的命令,置于注释行的起始处(但前导的“”会被忽略)。
有三种类型的注释文档,它们对应于位于注释后面的元素:类、变量或者方法。也就是说,一个类注释正好位于一个类定义之前;变量注释正好位于变量定义之前;而一个方法定义正好位于一个方法定义的前面。
注意javadoc 只能为public(公共)和protected(受保护)成员处理注释文档。“private”和“friendly”(详见5 章)成员的注释会被忽略,我们看不到任何输出(也可以用-private 标记包括private 成员)。这样做是有道理的,因为只有public 和protected 成员才可在文件之外使用,这是客户程序员的希
望。然而,所有类注释都会包含到输出结果里。
8.3 嵌入HTML
javadoc 将HTML 命令传递给最终生成的HTML 文档。这便使我们能够充分利用HTML 的巨大威力。
/**
* <pre>
* System.out.println(new Date());
* </pre>
*/
亦可象在其他Web 文档里那样运用HTML,对普通文本进行格式化,使其更具条理、更加美观。
注意在文档注释中,位于一行最开头的星号会被javadoc 丢弃。同时丢弃的还有前导空格。javadoc 会对所有内容进行格式化,使其与标准的文档外观相符。不要将<h1>或<hr>这样的标题当作嵌入HTML 使用,因为javadoc 会插入自己的标题,我们给出的标题会与之冲撞。
8.4 @see:引用其他类
所有三种类型的注释文档都可包含@see 标记,它允许我们引用其他类里的文档。对于这个标记,javadoc 会生成相应的HTML,将其直接链接到其他文档。
@see 类名
@see 完整类名
@see 完整类名#方法名
每一格式都会在生成的文档里自动加入一个超链接的“See Also”条目。注意javadoc 不会检查我们指定的超链接,不会验证它们是否有效。
8.5 类文档标记
类文档还可以包括用于版本信息以及作者姓名的标记。类文档亦可用于“接
口”目的。
@version 版本信息。
@author 作者信息。
8.6 变量文档标记
变量文档只能包括嵌入的HTML 以及@see 引用。
8.7 方法文档标记
除嵌入HTML 和@see 引用之外,方法还允许使用针对参数、返回值以及异常的文档标记。
@param 参数名 说明
@return 说明
@exception 异常 说明
@deprecated
import java.util.*;
/** The first Thinking in Java example program.
* Lists system information on current machine.
* @author Bruce Eckel
* @author http://www.BruceEckel.com
* @version 1.0
*/
public class Property {
/** Sole entry point to class & application
* @param args array of string arguments
* @return No return value
* @exception exceptions No exceptions thrown
*/
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());
}
}
使用方法:
javadoc -d 生成的帮助文档存放目录 源文件名.java
通过IDEA生成Javadoc:
Tools –> Generate JavaDoc –>
注意要配置编码,如果不配送为生成乱码,还需要配置Output directory