This website requires JavaScript.

Core Java 读书笔记二:对象与类

对象

要想使用OOP, —定要清楚对象的三个主要特性:

  • 对象的行为(behavior) — 可以对对象施加哪些操作, 或可以对对象施加哪些方法?
  • 对象的状态 (state ) — 当施加那些方法时 对象如何响应?
  • 对象标识(identity ) — 如何辨别具有相同行为与状态的不同对象?

面向对象的程序设计概述

再类质检,常见的关系有:

  • 依赖("uses-a”)
  • 聚合("has-a”)
  • 继承("is-a”)

依赖(dependence),即“ uses-a”关系,是一种最明显的、最常见的关系。例如,Order 类使用 Account 类是因为 Order 对象需要访问 Account 对象查看信用状态。 但是 Item 类不依 赖于 Account 类, 这是因为 Item 对象与客户账户无关。因此,如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。应该尽可能地将相互依赖的类减至最少。如果类 A 不知道 B 的存在, 它就不会关心 B 的任何改变(这意味着 B 的改变不会导致 A 产生任何 bug )。 用软件工程的术语来说, 就是 让类之间的耦合度最小。

聚合(aggregation), 即“ has-a” 关系, 是一种具体且易于理解的关系。 例如, 一个 Order 对象包含一些 Item 对象。 聚合关系意味着类 A 的对象包含类 B 的对象。

继承(inheritance), 即“ is-a” 关系, 是一种用于表示特殊与一般关系的。例如,Rush Order 类由 Order 类继承而来。

表达类关系的UML符号

UML notation for class relationships

使用预定义类

对象与对象变量

构造器的名字应该与类名相同。因此 Date 类的构造器名为 Date。要想构造一个 Date 对 象, 需要在构造器前面加上 new 操作符, 如下所示:

new Date()

用户自定义类

隐式参数与显式参数

public void raiseSalary(double byPercent)
{
    double raise = salary * byPercent / 100;
    salary += raise; 
}

number007. raiseSalary(5) ;
double raise = nuaber007.salary * 5 / 100;
nuiber007.salary += raise;

aiseSalary方法有两个参数。第一个参数称为隐式(implicit) 参数,是出现在方法名前的 Employee类对象。第二个参数位于方法名后面括号中的数值,这是一个**显式(explicit)参数 **(有些人把隐式参数称为方法调用的目标或接收者。) 在每一个方法中, 关键字 this 表示隐式参数。 如果需要的话, 可以用下列方式编写 raiseSalary 方法:

public void raiseSalary(double byPercent)
{
    double raise = this.salary * byPercent / 100;
    this.salary += raise; 
}

有些程序员更偏爱这样的风格, 因为这样可以将实例域与局部变量明显地区分开来。

静态域与静态方法

工厂方法

静态方法还有另外一种常见的用途。 类似 LocalDate 和 NumberFormat 的类使用静态工厂方法 ( factory method) 来构造对象。 你已经见过工厂方法 LocalDate.now 和 LocalDate.o。f NumberFormat 类如下使用工厂方法生成不同风格的格式化对象:

NumberFormat currencyFormatter = NumberFormat.getCurrencylnstance(); 
NumberFormat percentFormatter = NumberFormat.getPercentlnstance();
double x = 0.1; 
System.out.println(currencyFormatter.format(x)); // prints $0.10
System.out.println(percentFomatter.format(x)); // prints 10%

为什么 NumberFormat 类不利用构造器完成这些操作呢? 这主要有两个原因:

  • 无法命名构造器。 构造器的名字必须与类名相同。但是, 这里希望将得到的货币实例和百分比实例采用不用的名字。
  • 当使用构造器时, 无法改变所构造的对象类型。 而 Factory 方法将返回一个 DecimalFormat类对象,这是 NumberFormat 的子类。

方法参数

Java 程序设计语言总是采用按值调用。 也就是说,方法得到的是所有参数值的一个拷贝,特别是, 方法不能修改传递给它的任何参数变量的内容。

一个方法不可能修改一个基本数据类型的参数。 而对象引用作为参数就不同了, 可以很容易地利用下面这个方法实现将一个雇员的薪金提高两倍的操作:

public static void tripieSalary(Employee x) // works
{
    x.raiseSa1ary(200) ; 
}

harry = new Employee(. . .); 
tripieSalary(harry) ;

Java 允许使用包 ( package )将类组织起来。 借助于包可以方便地组织自己的代码, 并将 自己的代码与别人提供的代码库分开管理。

使用包的主要原因是确保类名的唯一性。 假如两个程序员不约而同地建立了 Employee 类。 只要将这些类放置在不同的包中, 就不会产生冲突。 事实上, 为了保证包名的绝对 唯一性, Sun 公司建议将公司的因特网域名 (这显然是独一无二的) 以逆序的形式作为包名,并且对于不同的项目使用不同的子包。

将类放入包中

要想将一个类放人包中, 就必须将包的名字放在源文件的开头, 包中定义类的代码之 前。 例如:

package com.horstiann.corejava; 

public class Employee
{
  ...
}

设置类路径

最好采用 -classpath ( 或 -cp ) 选项指定类路径:

java -classpath /home/user/dassdir:.:/home/user/archives/archive.jar HyProg
或者
java -classpath c:\classdir;.;c:\archives\archive.jar MyProg

利用 -dasspath 选项设置类路径是首选的方法, 也可以通过设置 CLASSPATH 环境变量 完成这个操作。其详细情况依赖于所使用的 shell 在 bash 中, 命令格式如下:

export CLASSPATH=/home/user/classdir:.:/home/user/archives/archive.jar

在Windowsshell, 命令格式如下:

set CLASSPATH=c:\classdir;.;c:\archives\archive.jar

直到退出 shell 为止, 类路径设置均有效。

文档注释

注释的插入

注释应该放置在所描述特性的前面。 注释以 /** 开始, 并以 / 结束。 每个 /* . . . */ 文档注释在标记之后紧跟着自由格式文本 ( free-form text )。 标记由 @ 开始,如 @author 或 @param。 自由格式文本的第一句应该是一个概要性的句子。javadoc 实用程序自动地将这些句子抽 取出来形成概要页。 在自由格式文本中, 可以使用 HTML 修饰符, 例如, 用于强调的 <em>...</em>、用于 着重强调的 <strong>...</strong> 以及包含图像的 <img ...> 等。不过, 一定不要使用 <h1><hr>, 因为它们会与文档的格式产生冲突。若要键入等宽代码,需使用{@code...}而不是 <code>...</code> 这样一来, 就不用操心对代码中的 < 字符转义了。

如果文档中有到其他文件的链接 例如 图像文件(用户界面的组件的图表或图像等), 就应该将这些文件放到子目录 doc-files 中。javadoc 实用程序将从源目录拷贝这 些目录及其中的文件到文档目录中。在链接中需要使用 doc-files 目录, 例如: <img src="doc-files/uml_png" alt="UML diagram" >

类注释

类注释必须放在 import 语句之后,类定义之前。下面是一个类注释的例子:

/**
* A {@code Card} object represents a playing card, such
* as "Queen of Hearts". A card has a suit (Diamond, Heart,
* Spade or Club) and a value (1 = Ace, 2 . . . 10, 11 = Jack, * 12 = Queen, 13 = King)
*/
public class Card
{
  ...
}

方法注释

每一个方法注释必须放在所描述的方法之前。 除了通用标记之外, 还可以使用下面的标记:

  • @param 变量描述:这个标记将对当前方法的“ param” (参数)部分添加一个条目。这个描述可以占据多行, 并可以使用 HTML 标记。一个方法的所有 @param 标记必须放在一起。
  • @return 描述:这个标记将对当前方法添加“ return” (返回)部分。这个描述可以跨越多行, 并可以使用 HTML 标记。
  • ©throws 类描述:这个标记将添加一个注释, 用于表示这个方法有可能抛出异常。

下面是一个方法注释的示例:

/**
* Raises the salary of an employee.
* @param byPercent the percentage by which to raise the salary (e.g. 10 means 10%) 
* @return the amount of the raise
*/
public double raiseSalary(double byPercent) {
double raise = salary * byPercent / 100; salary += raise;
return raise;
}

域注释

只需要对公有域 (通常指的是静态常量)建立文档。 例如

/**
* The "Hearts" card suit
*/
public static final int HEARTS = 1;

通用注释

下面的标记可以用在类文档的注释中:

  • @author 姓名:这个标记将产生一个"author" ( 作者)条目。可以使用多个 @aUthor 标记, 每个 @author 标记对应一个作者。
  • @version 文本:这个标记将产生一个“ version ”(版本)条目。 这里的文本可以是对当前版本的任何描述。

下面的标记可以用于所有的文档注释中:

  • @sinee 文本:这个标记将产生一个“since” (始于)条目。这里的 text 可以是对引人特性的版本描 述 例如 @since version 1.7.10
  • @deprecated 文本:这个标记将对类、方法或变量添加一个不再使用的注释。 文本中给出了取代的建议。 例如,@deprecated Use <code> setVIsible(true) </code> instead 通过 @see 和 @link 标记, 可以使用超级链接, 链接到 javadoc 文档的相关部分或外部文档。
  • @see引用:这个标记将在“ see also” 部分增加一个超级链接。它可以用于类中, 也可以用于方 法中。 这里的引用可以选择下列情形之一:package, class#feature label<a href="...">label</a>,"text"第一种情况是最常见的。 只要提供类、方法或变量的名字,javadoc 就在文档中插入 一个超链接。 例如,@see com.horstraann.corejava.Employee#raiseSalary(double)建立一个链接到 com.horstmann.corejava.Employee 类的 raiseSalary(double) 方法的超 链接。 可以省略包名, 甚至把包名和类名都省去, 此时, 链接将定位于当前包或当前类。 需要注意, 一定要使用井号(#), 而不要使用句号(.)分隔类名与方法名, 或类名与变量名。Java 编译器本身可以熟练地断定句点在分隔包、 子包、类、内部类与方法和变量时的不同含义。 但是 javadoc 实用程序就没有这么聪明了,因此必须对它提供帮助。如果 @see 标记后面有一个 < 字符, 就需要指定一个超链接。 可以超链接到任何 URL。 例如: @see <a href="www.horstmann.com/corejava.html">The Core ]ava home page</a> 在上述各种情况下, 都可以指定一个可选的标签(label) 作为链接锚(link anchor) o 如果省略了 label , 用户看到的锚的名称就是目标代码名或 URL。如果 @see 标记后面有一个双引号(")字符, 文本就会显示在 “ see also” 部分。 例如,@see "Core Java 2 volume 2"可以为一个特性添加多个 @see 标记, 但必须将它们放在一起。
  • 如果愿意的话, 还可以在注释中的任何位置放置指向其他类或方法的超级链接, 以及插人一个专用的标记, 例如,{@link package,class#feature label}这里的特性描述规则与 @see 标记规则一样。

包与概述注释

可以直接将类、方法和变量的注释放置在 Java 源文件中, 只要用 /** . . . */ 文档注释界 定就可以了。但是,要想产生包注释, 就需要在每一个包目录中添加一个单独的文件。可以 有如下两个选择:

  1. 提供一个以 package.html 命名的 HTML 文件。在标记 <body>...</body> 之间的所有 文本都会被抽取出来。
  2. 提供一个以 package-info.java 命名的 Java 文件。 这个文件必须包含一个初始的以 /** 和 */ 界定的 Javadoc 注释, 跟随在一个包语句之后。它不应该包含更多的代码或注释。

还可以为所有的源文件提供一个概述性的注释。 这个注释将被放置在一个名为 overview, html 的文件中, 这个文件位于包含所有源文件的父目录中。标记 <body>... </body> 之间的所有文本将被抽取出来。 当用户从导航栏中选择“ Overview ” 时,就会显示出这些注释内容。

注释的抽取

这里,假设 HTML 文件将被存放在目录 docDirectory 下。 执行以下步骤:

  1. 切换到包含想要生成文档的源文件目录。 如果有嵌套的包要生成文档, 例如 com.horstmann.corejava, 就必须切换到包含子目录com的目录(如果存在overview.html文件的 话, 这也是它的所在目录 )。
  2. 如果是一个包,应该运行命令:
javadoc -d docDirectory nameOfPackage

或对于多个包生成文档, 运行 :

javadoc -d docDirectory nameOfPackage nameOfPackage . . .

如果文件在默认包中, 就应该运行:

javadoc -d docDirectory *.java

如果省略了 -d docDirectory 选项, 那 HTML 文件就会被提取到当前目录下。 这样有可能会带来混乱, 因此不提倡这种做法。

可以使用多种形式的命令行选项对 javadoc 程序进行调整。 例如, 可以使用 -author 和 -version 选项在文档中包含 @author 和 @version 标记 (默认情况下,这些标记会被省 略)。另一个很有用的选项是-link, 用来为标准类添加超链接。例如,如果使用命令javadoc -link http://docs.oracle.eom/:javase/8/docs/api *.java那么, 所有的标准类库类都会自动地链接到 Oracle 网站的文档。如果使用 -linksource 选项, 则每个源文件被转换为 HTML ( 不对代码着色, 但包含行编号) 并且每个类和方法名将转变为指向源代码的超链接。有关其他的选项, 请查阅 javadoc 实用程序的联机文档

如果需要进一步的定制, 例如, 生成非 HTML 格式的文档, 可以提供自定义的 doclet, 以便生成想要的任何输出形式。显然, 这是一种特殊的需求, 有关细节内容请查阅联机文档

0条评论
avatar