`
bsr1983
  • 浏览: 1100823 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

第四章 对象与类

阅读更多
4.1 面向对象程序设计概述
4.1.1 OOP词汇表
类是构造对象的模板或蓝图。由类构造对象的过程被称为创建类的实例。
实现封装的关键在于绝不能让类中的方法直接访问其他类的实例域,但可以访问它自己的实例域。
通过扩展一个类来建立另外一个类的过程被称为继承。
4.1.2 对象
要想使用OOP,一定要清楚对象的三个主要特性:
(1)对象的行为(behavior)——可以对对象施加哪些操作,或可以对对象施加哪些方法?
(2)对象的状态(state)——当施加那些方法是,对象如何响应?
(3)对象的标示(identity)——如何区分具有相同行为与状态的不同对象?
同一个类的所有对象实例由于支持相同的行为而具有家族的相似性。对象的行为是用可调用的方法定义的。此外,每个对象都保存这描述当前特征的信息,这就是对象的状态。对象的状态可能会随着时间而发生改变,但这种改变不会是自发的。对象状态的改变必须通过调用方法实现。(如果没有经过方法调用而改变对象状态,就说明封装性一定遭到了破坏。)
作为一个类的实例,每个对象的标识永远是不同的,但状态却常常存在着差异。
提示:识别类的简单规则是在分析问题的过程中寻找名词。另一方面,方法对应着动词。
4.1.3 类之间的关系
在类之间,最常见的关系有
(1)依赖(“uses-a”)
(2)聚合(“has-a”)
(3)继承(“is-a”)
如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。
继承,即“is-a”关系,是一种用来表示特殊与一般关系的。
4.1.4 OOP与传统的过程化程序设计技术对比
对于规模较大的问题,使用类和方法将会带来两点好处。一是类提供了一种便于将众多的方法聚集在一起的机制。二是类的封装机制将有助于对其他的类方法隐藏数据表示。
4.2 使用现有类 2010-08-31 91页
4.2.1 对象与对象变量
要想使用对象,就必须首先构造对象,并指定其初始状态。然后,对对象施加方法。
在Java程序设计语言中,使用构造器(constructor)构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。
一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。
在Java中,任何对象变量的值都是对存储在另外一处的一个对象的引用。New操作符的返回值也是一个引用。
可以显式地将对象变量设置为空(null),表明这个对象变量目前没有引用任何对象。
变量不会自动地初始化为null,而必须对它们进行初始化,调用new或将它们设置为null。
所有的Java对象都存储在堆中,当一个对象包含另一个对象变量时,这个变量仍然包含的是指向另一个堆对象的指针。
4.2.2 Java库中的GregorianCalendar类
时间是用一个距离一个固定时间点的毫秒数(可正可负)表示的,这个点就是所谓的纪元(epoch)。它是UTC时间1970年1月1日00:00:00.
4.2.3 更改器方法与访问器方法
对实例域做出修改的方法被称为更改器方法,仅访问实例域而不加修改的方法被称为访问器方法。
4.3 用户自定义类
4.3.1 一个Employee类
在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。
4.3.2 多个源文件的使用
一次编多个java文件时,可以使用的方法有两种:一种是使用通配符调用Java编译器:
javac Employee*.java
另一种就是直接编译EmployeeTest.java,由于该类中使用了Employee类,因此在编译时Java编译器会先查找其对应的class,如果没有自动编译其源文件。
注意:如果熟悉UNIX的“make”工具(或者是Windows中的“namke”等工具),就可以认为Java内置了“make”功能。
4.3.3 解析Employee类
4.3.4 从构造器开始
1、构造器与类同名
2、每个类可以有一个以上的构造器
3、构造器可以有0个、1个或1个以上的构造器
4、构造器没有返回值
5、构造器总是伴随着new操作符一同使用
   必须注意在所有的方法中不要命名与实例域同名的变量。
4.3.5 隐式参数与显式参数
显式参数是明显地列在方法声明中的显示参数,隐式参数是没有出现在方法声明中的参数。在一个方法中,关键字this表示隐式参数。
在Java程序设计语言中,所有的方法都必须在类的内部定义,但并不表示它们是内联方法,是否将某个方法设置为内联方法是Java虚拟机的任务。即时编译器会监视调用那些简洁、经常被调用、没有被重载以及可优化的方法。
4.3.6 封装的优点
提示:注意不要编写返回引用可变对象的访问器方法。如果需要返回一个可变对象的引用,首先应该对它进行克隆(clone)。对象克隆是指存放在另一个位置上的对象副本。
4.3.7 基于基类的访问权限
4.3.8 私有方法
4.3.9 final实例域
可以将实例域定义为final。构建对象时必须初始化这样的域。也就是说,必须确保在每一个构造器执行之后,这个域的值被设置,并且在后面的操作中,不能够再对它进行修改。
Final修饰符大都应用于基本数据(primitive)类型域,或不可变(immutable)类的域。(如果类中的每个方法都不会改变其对象,这种累就是不可变的类。例如,String类就是一个不可变的类。)
4.4 静态域与静态方法
4.4.1 静态域
如果将域定义为static,那么每个类中只有一个这样的域。而每一个对象对于所有的实例域却都有自己的一份拷贝。
注意:在绝大多数的面向对象程序设计语言中,静态域被称为类域。术语“static”只是沿用了C++的叫法,并无实际意义。
4.4.2 静态常量
注意:如果查看一下System类,就会发现有一个setOut方法。它可以将System.out设置为不同的流。可能你会感到奇怪,为什么这个方法可以修改final变量的值。原因在于,setOut方法是一个本地方法,而不是用Java语言实现的。本地方法可以绕过Java语言的存取控制机制,只是一种特殊的方法,在自己编写程序时,不应该这样处理。
4.4.3 静态方法
静态方法是不能向对象实施操作的方法。可以认为静态方法是没有this参数的方法。(在一个非静态的方法中,this参数表示该方法的隐式参数。)
因为静态方法不能操作对象,所以不能在静态方法中访问实例域。但是,静态方法可以访问自身类中的静态域。
在下面两种情况下使用静态方法:
1、当一个方法不需要访问对象状态,其所需的参数都是通过显式参数提供的。
2、当一个方法只需要访问类的静态域。
Static含义:属于类且不属于类对象的变量和函数。
4.4.4 Factory方法
NumberFormat类不利用构造器而使用Factory方法的原因:
1、无法命名构造器。构造器的名字必须与类名相同。但是这里希望讲的到的货币实例和百分比实例采用不同的名字。
2、当使用构造器时,无法改变所构造的对象类型。而Factory方法将返回一个DecimalFormat类对象,这是NumberFormat的子类。
4.4.5 main方法
main方法不对任何对象进行操作。事实上,在启动程序的时候还没有任何一个对象。静态的main方法将执行被创建程序所需要的对象。
4.5 方法参数
值调用(call by value)表示方法接收的是调用者提供的值
引用调用(call by reference)表示方法接收的是调用者提供的变量位置。
一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
Java程序设计语言使用值调用,也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。
总结一下再Java程序设计语言中,方法参数的使用情况:
1、一个方法不能修改一个基本数据类型的参数(即数值型和布尔型)。
2、一个方法可以改变一个对象参数的状态。
3、一个方法不能让对象参数引用一个新的对象。
4.6 对象构造
4.6.1 重载
如果多个方法有相同的名字、不同的参数,便产生了重载。
注意:Java允许重载任何方法,而不仅仅是构造器方法。因此,要完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。
4.6.2 默认域初始化
如果在构造中没有显示地给域赋初值,它就会被自动地赋为默认值:数值为0、布尔值为false、对象为null。
注意:这是域与局部变量的主要不同点。必须名曲地初始化方法中的局部变量。但是如果没有初始化类中的域,将会被初始化为默认值。
4.6.3 默认构造器
所谓默认构造器是指没有参数的构造器。
如果在编写一个类时没有编写构造器,系统就会提供一个默认构造器。这个默认构造器将所有的实例域设置为默认值。
4.6.4 显式域初始化
class Employee
{
private String name="";
}
当一个类的所有构造器都希望将相同的值赋予每个特定的实例域是,这种方式特别有用。
4.6.5 参数名
4.6.6 调用另一个构造器
关键字this引用方法的隐式参数。如果构造器的第一个语句形如this(...),那么这个构造器将调用同一个类的另一个构造器。
4.6.7 初始化块
由于初始化数据域有多种途径,所以列出构造过程的所有路径可能相当混乱。下面是构造器的具体处理步骤:
(1)所有数据域被初始化为默认值
(2)按照在累什么中出现的次序依次执行所有域初始化语句和初始化块
(3)如果构造器第一行调用了第二个构造器,则执行第二个构造器主体。
(4)执行这个构造器的主体。
如果对类的静态域进行初始化的代码比较复杂,就可以使用静态的初始化块。将代码放置在一个块中,并标记关键字static。
4.6.8 对象析构与finalize方法
可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前被调用。在实际应用中,不要使用finalize方法回收任何短缺的资源,因为很难知道这个方法什么时候才能够被调用。
注意:有个名为System.renFinalizersOnExit(true)的方法能够确保finalizer方法在Java关闭之前被调用,不过,这个方法并不安全,也不鼓励大家使用。有一种替代的方法是使用方法Runtime.addShutdownHook添加“关闭钩”(shutdown hook)。
4.7 包 2010-09-03 126页
包嵌套的唯一目的是管理唯一的名字。从编译器的角度来看,嵌套的包之间没有任何关系。
4.7.1 类的导入
一个类可以使用所属保重的所有类,以及其他包中的共有类。
import语句是一种引用包含在包中的类简明描述。
在包中定位类是编译器的工作。类文件中的字节码肯定使用完整的包名来引用其他类。
4.7.2 静态导入
从JDK5.0开始,import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。
4.7.3 将类放入包中
要想将一个类放入包中,就必须将包的名字放在源文件的开头,包中定义类的代码之前。
4.7.4 虚拟机如何定位类
提示:JAR文件使用ZIP格式组织文件和子目录。可以使用所有ZIP实用程序查看内部的rt.jar以及其他的JAR文件。
类路径是左右基目录的集合,基目录中的子目录可以用于包含类文件。
如何设置类路径将取决于编译环境。如果使用JDK,那么就有两种选择:为编译器和字节码解释器指定-classpath选项,或者设置CLASSPATH环境变量。
4.7.5 包作用域
从1.2版开始,JDK的实现者修改了类加载器,明确地禁止加载用户自定义的,包名以“java”开始的类!
4.8 文档注释
4.8.1 注释的插入
javadoc实用程序(utility)从下面几个特性抽取信息:
1、包
2、公有类与接口
3、公有的和受保护的(protected)方法
4、公有的和受保护的域
4.8.2 类注释
4.8.3 方法注释
每个方法注释必须放置在所描述的方法之前。
4.8.4 域注释
只需要对公有域(通常指的是静态常量)建立文档。
4.8.5 通用注释
4.8.6 包与概述注释
要想产生包注释,就需要在每一个包目录中添加一个名为package.html的文件。在标记<BODY></BODY>之间的所有文本都会被抽取出来。
4.8.7 注释的抽取
4.9 类设计技巧
1)一定将数据设计为私有。
2)一定要对数据初始化。
3)不要在类中使用过多的基本数据类型。
4)不是所有的域都需要独立的域访问器和域更改器。
5)使用标准格式进行类的定义。
6)将职责过多的类进行分解。
7)类名和方法名要能够体现它们的职责。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics