sql server jar包_失眠架构师带你学java核心技术:包+文档注释+类设计技巧,学吗?...

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

标准的Java类库分布在多个包中,包括java.lang、java.util、java.net等等。标准的Java包具有一个层次结构。如同硬盘的目录嵌套一样,也可以使用嵌套层次组织包。所有标准的Java包都处于java和javax包层次中。

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

包嵌套的唯一目的是管理唯一的名字。从编译器的角度来看,嵌套的包之间没有任何关系。

例如,java.util包与java.util.jar包毫无关系。每一个都拥有独立的类集合。

类的导入

一个类可以使用所属包中的所有类,以及其他包中的公有类。我们可以采用两种方式访问另一个包中的公有类。第一种方式是在每个类名之前添加完整的包名。例如:

java.util.Date today = new java.util.Date( );

这显然很令人生厌。更简单且更常用的方式是使用import语句。import语句是一种引用包含在包中的类的简明描述。一旦使用了import语句,在使用类时,就不必写出包的全名了。

可以使用import语句导入一个特定的类或者整个包。import语句应该位于源文件的顶部(但位于package语句的后面)。例如,可以使用下面这条语句导入java.util包中所有的类。

import java.util.*;

然后,就可以使用

Date today = new Date( );

而无需在前面加上包前缀。还可以导入一个包中的特定类:

import java.util.Date;

java.util.*的语法比较简单,对代码的大小也没有任何负面影响。当然,如果能够明确地指出所导入的类,将会使读者更加准确地知道加载了哪些类。

但是,需要注意的是,只能使用星号(*)导入一个包,而不能使用import java.*或importjava.*.*来导入以java为前缀的所有包。

在大多数情况下,只导入所需的包,并不必过多地理睬它们。但在发生命名冲突的时候,就不能不注意包的名字了。例如,java.util和java.sql包都有日期(Date)类。如果在程序中导入了这两个包

import java.util.*;

import java.sql.*;

在程序使用Date类的时候,就会出现一个编译错误:

Date today; // ERROR--java.util.Date or java.sql.Date?

编译器无法确定程序使用的是哪一个Date类。可以采用增加一个特定的import语句来解决这个问题:

import java.util.*;

import java.sql.*;

import java.util.Date;

如果这两个Date类都需要使用,又该怎么办呢?答案是,在每个类名的前面加上完整的包名。

java.util.Date deadline = new java.util.Date( );

java.sql.Date today = new java.sql.Date(...);

在包中定位类是编译器的工作。类文件中的字节码肯定使用完整的包名来引用其他类。

静态导入

从JDK 5.0开始,import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。

例如,如果在源文件的顶部,添加一条指令:

import static java.lang.System.*;

那么就可以使用System类的静态方法和静态域,而不必加类名前缀:

out.println("Goodbye, World!"); // i.e., System.out

exit(0); // i.e., System.exit

另外,还可以导入特定的方法或域:

import static java.lang.System.out;

实际上,是否有更多的程序员采用System.out或System.exit的简写形式,似乎是一件值得怀疑的事情。这种编写形式无益于代码的清晰度。不过,导入静态方法和导入静态域有两个实际的应用。

1)算术函数:如果对Math类使用静态导入,就可以采用更加自然的方式使用算术函数。例如,

sqrt(pow(x, 2) + pow(y, 2))

看起来比

Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))

清晰得多。

2)笨重的常量:如果需要使用大量带有冗长名字的常量,就应该使用静态导入。例如,

if (d.get(DAY_OF_WEEK) == MONDAY)

看起来比

if (d.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY)

容易得多。

将类放入包中

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

例如,例4-7中的文件Employee.java开头是这样的:

package com.horstmann.corejava;

public class Employee

{

. . .

}

如果没有在源文件中放置package语句,那么这个源文件中的类就被放置在一个默认包中。默认包是一个没有名字的包。在此之前,我们定义的所有类都在默认包中。

将包中的文件放到与完整的包名匹配的子目录中。例如,com.horstmann.corejava包中的所有类文件应该被放置在子目录com/horstmann/corejava(Windows中com\horstmann\corejava)中。

例4-6和例4-7中的程序分放在两个包中:PackageTest类放置在默认包中;Employee类放置在com.horstmann.corejava包中。因此,Employee.class文件必须包含在子目录com/horstmann/corejava中。

换句话说,目录结构如下所示:

基目录

5eea1e69276811e7a69996696bd6ee8c.png

要想编译这个程序,只需改变基目录,并运行命令

javac PackageTest.java

编译器就会自动地查找文件com/horstmann/corejava/Employee.java并进行编译。

下面看一个更加实际的例子。在这里不使用默认包,而将类分放在不同的包中(com.horstmann.corejava和com.mycompany)。

基目录

3572876ee7ccacd7a0e9058b253efac2.png

在这种情况下,仍然要从基目录编译和运行类,即包含com目录:

javac com/mycompany/PayrollApp.java

java com.mycompany.PayrollApp

需要注意,编译器对(带有文件分隔符和扩展名.java的)文件进行操作。而Java解释器加载类(带有.分隔符)。

例4-6 PackageTest.java

b883441411ce0ce0d8a7d9eb064276ca.png

例4-7 Employee.java

3e004de15dc9cf2f13540e03ad08869f.png

a0b252a124f6e61599cd0e66361ddd58.png

虚拟机如何定位类

在前面已经看到,类存储在文件系统的子目录中。类的路径必须与包名匹配。另外,还可以利用JAR实用程序将类文件添加到归档文件中。在一个归档文件中,可以包含多个类文件和子目录,这样既可以节省又可以改善性能。(有关JAR文件的详细内容将在第10章中讨论。)

例如,在运行时库中的数千个类都包含在运行时库文件rt.jar中。在JDK的jre/lib子目录中可以找到这个文件。

在前面的例子程序中,包目录com/horstmann/corejava是程序目录的一个子目录。但是,这样的安排缺乏灵活性。通常,可能会有多个程序访问包文件,为了能够使程序共享包,需要做到下面几点:

1)把类放到一个或多个指定的目录中,例如/home/user/classdir。需要注意,这个目录是包树状结构的基目录。如果希望将com.horstmann.corejava.Employee类添加到其中,这个类文件就必须位于子目录 /home/user/classdir/com/horstmann/corejava中。

2)设置类路径。类路径是所有基目录的集合,基目录中的子目录可以用于包含类文件。

如何设置类路径将取决于编译环境。如果使用JDK,那么就有两种选择:为编译器和字节码解释器指定 -classpath选项,或者设置CLASSPATH环境变量。

具体的设置细节将取决于所用的操作系统。在 UNIX环境中,类路径中的不同项目之间是采用冒号(:)分隔的。

/home/user/classdir:.:/home/user/archives/archive.jar

在 Windows环境中,将以分号(;)分隔。

c:\classes;.;c:\archives\archive.jar

在上述两种情况中,句点(.)表示当前目录。

类路径包括:

• 基目录 /home/user/classdir或c:\classes;。

• 当前目录 (.);。

• JAR文件 /home/user/archives/archive.jar或c:\archives\archive.jar。

由于运行时库文件(在jre/lib与jre/lib/ext目录下的rt.jar和一些其他的JAR文件)会被自动地搜索,所以不必将它们显式地列在类路径中。

包作用域

前面已经接触过访问修饰符public和private。标记为public的部分可以被任意的类使用;标记为private 的部分只能被定义它们的类使用。如果没有指定public或private,那么这个部分(类、方法或变量)可以被同一个包中的所有方法访问。

00d41a04455fb7a6ca3e01df5527fae3.png

下面再仔细地看一下例4-2中的程序。在这个程序中,没有将Employee类定义为公有类,因此只有在同一个包(在此是默认包)中的其他类可以访问,例如EmployeeTest。对于类来说,这种默认是合乎情理的。但是,对于变量来说就有些不适宜了,因此变量必须显式地标记为private,不然的话将默认为包可见。显然,这样做会破坏封装性。问题主要出于人们经常忘记键入关键字private。在java.awt包中的Window类就是一个典型的例子。java.awt包是JDK提供的源代码的一部分:

public class Window extends Container

{

String warningString;

. . .

}

请注意,这里的warningString变量不是private!这意味着java.awt包中的所有类的方法都可以访问该变量,并将它设置为任意值(例如,“Trust me!”)。实际上,只有Window类的方法才访问它,因此应该将它设置为私有变量。我们猜测可能是程序员匆忙之中忘记键入private修饰符了。(为防止程序员内疚,我们没有说出他的名字,感兴趣的话,可以查看一下源代码。)

文档注释

JDK包含一个很有用的工具,叫做javadoc,它可以由源文件生成一个HTML文档。事实上,在第3章讲述的联机API 文档就是通过对标准Java类库的源代码运行javadoc生成的。

如果在源代码中添加以专用的定界符 /** 开始的注释,就可以很容易地生成一个看上去具有专业水准的文档。这是一种很好的方式,因为这种方式可以将代码与注释保存在一个地方。如果将文档存入一个独立的文件中,就有可能会随着时间的推移,出现代码和注释不一致的问题。然而,由于文档注释与源代码在同一个文件中,在修改源代码的同时,重新运行javadoc就可以轻而易举地保持两者的一致性。

注释的插入

javadoc实用程序(utility)从下面几个特性抽取信息:

• 包

• 公有类与接口

• 公有的和受保护的(protected)方法

• 公有的和受保护的域

在第5章中将介绍受保护特性,接口将在第6章介绍。

应该为上述几部分编写注释。注释应该放置在所描述特性的前面。注释以 /** 开始,并以 */结束。

每个 /** . . . */ 文档注释在标记之后紧跟着自由格式文本(free-form text)。标记由 @ 开始,如@author或@param。

自由格式文本的第一句应该是一个概要性的句子。javadoc实用程序自动地将这些句子抽取出来形成概要页。

在自由格式文本中,可以使用HTML修饰符,如用于强调的 ...、用于设置等宽

“打字机”字体的 ...、用于着重强调的 ... 以及包含图像的 等。

不过,一定不要使用

或 ,因为它们将与文档的格式产生冲突。

类注释

类注释必须放置在import语句之后,类定义之前。

下面是一个类注释的例子:

1acf9594416c46ba3a0a70517aafe2b7.png

方法注释

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

@param variable description

这个标记将向当前方法的“param”(参数)部分添加一个条目。这个描述可以占据多行,并可以使用HTML标记。一个方法的所有 @param 标记必须放在一起。

@return description

这个标记将向当前方法添加“return”(返回)部分。这个描述可以跨越多行,并可以使用HTML标记。

@throws class description

这个标记将添加一个注释,用于表示这个方法有可能抛出异常。有关异常的详细内容将在第11章中讨论。

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

2dac85d4e0346964ddd0cc46f4118d3e.png

域注释

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

通用注释

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

@author name

这个标记将产生一个“author”(作者)条目。可以使用多个 @author 标记,每个 @author 标记对应一名作者。

@version text

这个标记将产生一个“version”(版本)条目。这里的text可以是对当前版本的任何描述。

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

@since text

这个标记将产生一个“since”(始于)条目。这里的text可以是对引入特性的版本描述。例如,

@since version 1.7.1。

@deprecated text

这个标记将对类、方法或变量添加一个不再使用的注释。text中给出了取代的建议。例如,

@deprecated Use setVisible(true) instead

通过 @see 和 @link 标记,可以使用超级链接,链接到javadoc文档的相关部分或外部文档。

@see reference

这个标记将在“see also”部分增加一个超级链接。它可以用于类中,也可以用于方法中。

这里的reference可以选择下列情形之一:

• package.class#feature label

label

• "text"

第一种情况是最常见的。只要提供类、方法或变量的名字,javadoc就在文档中插入一个超链接。例如,

@see com.horstmann.corejava.Employee#raiseSalary(double)

建立一个链接到com.horstmann.corejava.Employee类的raiseSalary(double)方法的超链接。可以省略包名,甚至把包名和类名都省去,此时,链接将定位于当前包或当前类。

需要注意,一定要使用井号(#),而不要使用句号(.)来分隔类名与方法名,或类名与变量名。Java编译器本身可以熟练地断定句点在分隔包、子包、类、内部类与方法和变量时的不同含义。但是javadoc实用程序就没有这么聪明了,因此必须对它提供帮助。

如果@see标记后面有一个 < 字符,就需要指定一个超链接。可以超链接到任何URL。例如,

@see The Core Java home page

在上述各种情况下,都可以指定一个可选的标签(label)作为链接锚(link anchor)。如果省略了label,那么用户看到的锚的名称就是目标代码名或URL。

如果 @see 标记后面有一个双引号(")字符,文本就会显示在“see also”部分。例如,

@see "Core Java 2 volume 2"

可以为一个特性添加多个 @see 标记,但必须将它们放在一起。

如果愿意的话,还可以在注释中的任何位置放置指向其他类或方法的超级链接,以及插入一个专用的标记,例如,{@link package.class#feature label}。这里的特性描述规则与@see标记规则一样。

包与概述注释

可以直接将类、方法和变量的注释放置在Java源文件中,只要用 /** . . . */ 文档注释界定就可

以了。但是,要想产生包注释,就需要在每一个包目录中添加一个名为package.html的文件。在标

... 之间的所有文本都会被抽取出来。

还可以为所有的源文件提供一个概述性的注释。这个注释将被放置在一个名为overview.html

的文件中,该文件位于包含所有源文件的父目录中。标记

... 之间的所有文本将被

抽取出来。当用户从导航栏中选择“Overview”时,就会显示出这些注释内容。

注释的抽取

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

1)切换到包含想要生成文档的源文件目录。如果有嵌套的包要生成文档,例如com.horstmann.corejava,就必须切换到包含子目录com的目录。(如果存在overview.html文件的话,这也是它的所在目录。)

2)如果是一个包,应该运行命令:

javadoc -d docDirectory nameOfPackage

或运行:

javadoc -d docDirectory nameOfPackage1 nameOfPackage2 . . .

对于多个包生成文档。如果文件在默认包中,就应该运行:

javadoc -d docDirectory *. java

如果省略了-d docDirectory选项,HTML文件就被提取到当前目录下。这样有可能会带来混

乱,因此不提倡这种做法。

可以使用多种形式的命令行选项对javadoc程序进行调整。例如,可以使用 -author 和 -version

选项在文档中包含 @author和 @version标记。(默认情况下,这些标记会被省略。)另一个很有用

的选项是 -link,用来为标准类添加超链接。例如,如果使用命令

javadoc -link http://java.sun.com/j2se/5.0/docs/api *.java

那么,所有的标准类库类都会自动地链接到Sun网站的文档。

有关其他的选项,请查阅javadoc实用程序的联机文档,http://java.sun.com/j2se/javadoc。

类设计技巧

在结束本章之前,简单地介绍几点技巧。应用这些技巧可以使得设计出来的类更具有OOP的专业水准。

1)一定将数据设计为私有。

最重要的是:绝对不要破坏封装性。在有的时候,需要编写一个访问器方法或更改器方法,但是最好还是保持实例域的私有性。很多惨痛的经验告诉我们,数据的表示形式很可能会改变,但它们的使用方式却不会经常发生变化。当数据保持私有时,它们的表示形式的变化不会对类的使用者产生影响,即使出现bug也易于检测。

2)一定要对数据初始化。

Java不对局部变量进行初始化,但是会对对象的实例域进行初始化。最好不要依赖于系统的默认值,而是应该显式地初始化所有的数据,具体的初始化方式可以是提供默认值,也可以是在所有构造器中设置默认值。

3)不要在类中使用过多的基本数据类型。

就是说,用其他的类代替多个相关的基本数据类型的使用。这样会使类更加易于理解且易于修改。例如,用一个称为Address的类替换下面的Customer类中的实例域:

private String street;

private String city;

private String state;

private int zip;

这样,可以很容易地顺应地址的变化,例如,需要增加对国际地址的处理。

4)不是所有的域都需要独立的域访问器和域更改器。

或许,需要获得或设置雇员的薪金。而一旦构造了雇员对象,就应该禁止更改雇用日期,并且在对象中,常常包含一些不希望别人获得或设置的实例域,例如,在Address类中,存放州缩写的数组。

5)使用标准格式进行类的定义。

一定采用下面的顺序书写类的内容:

公有访问特性部分

包作用域访问特性部分

私有访问特性部分

在每一部分中,应该按照下列顺序列出:

实例方法

静态方法

实例域

静态域

毕竟,类的使用者对公有接口要比对私有的实现细节更感兴趣,并且对方法要比对数据更感兴趣。

但是,哪一种风格更好并没有达成共识。Sun的程序设计风格建议 Java程序设计语言先书写域,后书写方法。无论采用哪种风格,重要的一点是要保持一致。

6)将职责过多的类进行分解。

这样说似乎有点含糊不清,究竟多少算是“过多”?每个人的看法不同。但是,如果明显地可以将一个复杂的类分解成两个更为简单的类,就应该将其分解。(但另一方面,也不要走极端。设计10个类,每个类只有一个方法,显然也太小了。)

下面是一个反面的设计的例子。

d1095faf40d8ae5cfc6263aba106edbc.png

实际上,这个类实现了两个独立的概念:一副牌(含有shuffle方法和draw方法)、一张牌(含有查看面值和花色的方法)。另外,引入一个表示单张牌的Card类。现在有两个类,每个类完成自己的职责:

85847d55415ecea1f2cb96d89473a93e.png

c6b1a2ad3b59a76e01d191122b182ed8.png

7)类名和方法名要能够体现它们的职责。

与变量应该有一个能够反映其含义的名字一样,类也应该如此。(在标准类库中,也存在着一些含义不明确的例子,如:Date类实际上是一个用于描述时间的类。)

命名类名的良好习惯是采用一个名词(Order)、前面有形容词修饰的名词(RushOrder)或动名词(有“-ing”后缀)修饰名词(例如,BillingAddress)。对于方法来说,习惯是访问器方法用小写get开头(getSalary),更改器方法用小写的set开头(setSalary)。

觉得文章不错的话,可以转发此文关注小编,之后持续更新干货文章!!!

加油(ง •̀_•́)ง!!!

3ff6aa8470d1f4acb6720e901af56215.png

10年架构师深解java核心技术:方法参数+对象构造,确定不学?

Java核心技术:GregorianCalendar类+更改器方法与访问器方法大牛带你深入Java核心技术,进行面向对象程序设计深剖,可以一学

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值