前言
Java开发工具包(JavaDevelopment Kit)
第四章 对象与类
4.1 面向对象程序设计概述
事实上,在 Java 中,所有的类都源自于一个“神通广大的超类”,它就是 Object。
首先从设计类开始,然后再往每个类中添加方法。
使用预定义类
构造器:
-
在 Java 程序设计语言中,使用构造器(constructor)构造新实例。
-
构造器的名字应该与类名相同。
在 Java 中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。new 操作符的返回值也是一个引用。
可以将 Java 的对象变量看作 C++ 的对象指针。
在 Java 中的 null 引用对应 C++ 中的 NULL 指针。
所有的 Java 对象都存储在堆中。
UTC,称为协调世界时。
时间是用距离一个固定时间点的毫秒数(可正可负)表示的,这个点就是所谓的纪元(epoch),它是 UTC 时间 1970 年 1 月 1 日 00:00:00。UTC 是Coordinated Universal Time的缩写
4.3 用户自定义类
在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。
强烈建议将实例域标记为private。
在 Java 中,所有的方法都必须在类的内部定义,但并不表示它们是内联方法。是否将某个方法设置为内联方法是 Java 虚拟机的任务。
应该将所有的数据域都设置为私有的。
可以将实例域定义为final。构建对象时必须初始化这样的域,并且在后面的操作中,不能够再对它进行修改。
4.4 静态域与静态方法
静态域 nextId 也存在。它属于类,而不属于任何独立的对象。
静态方法是一种不能向对象实施操作的方法。
在下面两种情况下使用静态方法:
-
一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(例如:Math.pow)。
-
一个方法只需要访问类的静态域(例如:Employee.getNextId)。
4.5 方法参数
Java 程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
方法参数共有两种类型:
-
基本数据类型(数字、布尔值)。
-
对象引用。
4.6 对象构造
如果多个方法(比如,StringBuilder 构造器方法)有相同的名字、不同的参数,便产生了重载。
Java 允许重载任何方法,而不只是构造器方法。因此,要完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。
返回类型不是方法签名的一部分。也就是说,不能有两个名字相同、参数类型也相同却返回不同类型值的方法。
如果在编写一个类时没有编写构造器,那么系统就会提供一个无参数构造器。这个构造器将所有的实例域设置为默认值。
如果类中提供了至少一个构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会被视为不合法。
在 Java 中,this 引用等价于 C++ 的 this 指针。
由于 Java 有自动的垃圾回收器,不需要人工回收内存,所以Java不支持析构器。
可以为任何一个类添加 finalize 方法。finalize 方法将在垃圾回收器清除对象之前调用。
4.7 包
Java 允许使用包(package)将类组织起来。
标准的 Java 类库分布在多个包中,包括 java.lang、java.util 和 java.net 等。标准的 Java 包具有一个层次结构。
所有标准的 Java 包都处于 java 和 javax 包层次中。
使用包的主要原因是确保类名的唯一性。
事实上,为了保证包名的绝对唯一性,Sun公司建议将公司的因特网域名(这显然是独一无二的)以逆序的形式作为包名,并且对于不同的项目使用不同的子包。
从编译器的角度来看,嵌套的包之间没有任何关系。例如,java.util 包与 java.util.jar 包毫无关系。
一个类可以使用所属包中的所有类,以及其他包中的公有类(public class)。
在 C++ 中,与包机制类似的是命名空间(namespace)。在 Java 中,package 与 import 语句类似于 C++ 中的 namespace 和 using 指令。
如果没有在源文件中放置 package 语句,这个源文件中的类就被放置在一个默认包(defaulf package)中。默认包是一个没有名字的包。在此之前,我们定义的所有类都在默认包中。
如果没有指定 public 或 private,这个部分(类、方法或变量)可以被同一个包中的所有方法访问。
从 1.2 版开始,JDK 的实现者修改了类加载器,明确地禁止加载用户自定义的、包名以 “java.” 开始的类。
4.9 文档注释
JDK 包含一个很有用的工具,叫做 javadoc,它可以由源文件生成一个 HTML 文档。
每个 /**...*/ 文 档注释在标记之后紧跟着自由格式文本(free-form text)。标记由 @ 开始,如 @author 或 @param。自由格式文本的第一句应该是一个概要性的句子。javadoc 实用程序自动地将这些句子抽取出来形成概要页。
在自由格式文本中,可以使用 HTML 修饰符,例如,用于强调的 ...、用于着重强调的 ... 以及包含图像的 <img...> 等。不过,一定不要使用 <h1>
或 <hr>
,因为它们会与文档的格式产生冲突。若要键入等宽代码,需使用 {@code...} 而不是 <code>...</code>
这样一来,就不用操心对代码中的 < 字符转义了。
-
@param变量描述
-
@return描述
-
@throws类描述
只需要对公有域(通常指的是静态常量)建立文档。
下面的标记可以用在类文档的注释中。
-
@author 姓名
-
@version 文本
可以直接将类、方法和变量的注释放置在 Java 源文件中,只要用 /**...*/ 文档注释界定就可以了。但是,要想产生包注释,就需要在每一个包目录中添加一个单独的文件。
可以有如下两个选择:
-
1、提供一个以 package.html 命名的 HTML 文件。在标记 ... 之间的所有文本都会被抽取出来。
-
2、提供一个以 package-info.java 命名的 Java 文件。这个文件必须包含一个初始的以 /* *和 */ 界定的 Javadoc 注释,跟随在一个包语句之后。它不应该包含更多的代码或注释。
4.10 类设计技巧
1.一定要保证数据私有这是最重要的;绝对不要破坏封装性。有时候,需要编写一个访问器方法或更改器方法,但是最好还是保持实例域的私有性。
2.一定要对数据初始化
3.不要在类中使用过多的基本类型,就是说,用其他的类代替多个相关的基本类型的使用。
4.不是所有的域都需要独立的域访问器和域更改器
5.将职责过多的类进行分解
6.类名和方法名要能够体现它们的职责
7.优先使用不可变的类,如果类是不可变的,就可以安全地在多个线程间共享其对象。
第五章 继承
5.1 类、超类和子类
Java 与 C++ 定义继承类的方式十分相似。Java 用关键字 extends 代替了 C++ 中的冒号(:)。在 Java 中,所有的继承都是公有继承,而没有 C++ 中的私有继承和保护继承。
在 Java 中使用关键字 super 调用超类的方法
使用 super 调用构造器的语句必须是子类构造器的第一条语句。
在覆盖一个方法的时候,子类方法不能低于超类方法的可见性。特别是,如果超类方法是 public,子类方法一定要声明为 public。
不允许扩展的类被称为 final 类。如果在定义类的时候使用了 final 修饰符就表明这个类是 final 类。
类中的特定方法也可以被声明为 final。如果这样做,子类就不能覆盖这个方法( final 类中的所有方法自动地成为 final 方法)。
如果将一个类声明为 final,只有其中的方法自动地成为 final,而不包括域。
将方法或类声明为 final 主要目的是:确保它们不会在子类中改变语义。
将一个子类的引用赋给一个超类变量,编译器是允许的。但将一个超类的引用赋给一个子类变量,必须进行类型转换,这样才能够通过运行时的检查。
只能在继承层次内进行类型转换。在将超类转换成子类之前,应该使用 instanceof 进行检查。
在一般情况下,应该尽量少用类型转换和 instanceof 运算符。
包含一个或多个抽象方法的类本身必须被声明为抽象的。
除了抽象方法之外,抽象类还可以包含具体数据和具体方法。
类即使不含抽象方法,也可以将类声明为抽象类。
抽象类不能被实例化,只能被继承。
大家都知道,最好将类中的域标记为 private,而方法标记为 public。
在有些时候,人们希望超类中的某些方法允许被子类访问,或允许子类的方法访问超类的某个域。为此,需要将这些方法或域声明为 protected。
事实上,Java 中的受保护部分对所有子类及同一个包中的所有其他类都可见。
归纳一下 Java 用于控制可见性的4个访问修饰符:
-
1)仅对本类可见——private。
-
2)对所有类可见——public。
-
3)对本包和所有子类可见——protected。
-
4)对本包可见——默认(很遗憾),不需要修饰符。