第四章 对象与类
1. 面向对象程序设计概述
●传统结构化程序设计和面向对象程序设计的区别:
传统的结构化程序设计:通过一系列的过程来求解问题,算法第一位,数据结构第二位
OOP:让每一个对象负责执行一组相关的任务,数据第一位,结构第二位
●对象之间的所有通信都是通过方法调用完成的。通过封装对象数据,最大限度的提高可重用性,减少数据的依赖性,并将程序的调试时间降到最短
●封装encapsulation(数据隐藏):将数据和行为结合在一个包中,并对对象的使用者隐蔽了数据的实现方式
●对象:
对象的行为:同一个类的对象实例由于支持相同的行为而具有家族的相似性
对象的状态:每个对象都保存着描述当前特征的信息,对象状态的改变必须通过调用方法实现
对象的标识:对象唯一的身份,作为一个类的实例,每个对象的标识永远是不同的,但状态却往往存在着差异
●类之间的关系:
依赖 (uses-a):一个类的方法操纵另一个类的对象
聚合(has-a):类A的对象包含类B的对象
继承(is-a):特殊与一般的关系
●OOP和传统过程化程序设计的对比:
在OOP中最重要的区别是首先从项目中分离出类,然后再找出这个类中需要定义哪些方法
类和方法带来的两点好处:
类提供了一种便于将众多的方法聚集在一起的机制
类的封装机制将有助于对其他的类方法隐藏数据表示
类可以拥有相同行为的多个对象,但我们却不能得到某个模块的多个拷贝
2. 使用现有类:
●对象与对象变量
Data deadline; 变量deadline是一个变量,实际上也没有引用对象
初始化的两个方法:
调用构造器来初始化变量
让这个变量引用一个已存在的变量
一个对象变量并没有实际包含一个对象,而仅仅引用一个对象
●GregorianCalendar类
存在原因:将时间与日历分开
3. 用户自定义类
★构造器总是伴随着new操作符的执行被调用,而不能对一个已经存在的对象调用构造器来重新设置实例域(这里便也道出了构造器只能调用一次)
不要在构造器中定义与实例域重名的局部变量(很通俗,但是如果不注意出错很难查出来)
●隐式参数与显示参数
隐式参数:出现在方法名前的对象
显式参数:出现在方法名后面括号中的数值
This是典型的隐式参数
●封装的优点
封装的好处:
改变内部实现,除了该类的方法外,不会影响其他代码
更改器方法可以执行错误检查,然而直接对域进行赋值将不会做这些处理
★不要编写返回引用可变对象的访问器方法
原因:由于对象仅仅是引用,所以对对象使用更改器方法实际是对私有对象进行操作
如果需要返回一个可变对象的引用,应该首先对它进行克隆,对象克隆是指存放在另一个位置上的对象副本
●基于类的访问权限
方法可以访问所调用对象的私有数据
一个方法可以访问所属类的所有对象的私有数据
●私有方法
只要方法是私有的,类的设计者就可以确信:他不会被外部的其他类操作调用,可以将其删去(私有方法的好处是类的所有者可以随意更改而不会影响到其它类的调用)
●final实例域
★对于final修饰的对象引用,仅仅表示变量中的对象饮用在对象构造后不能改变,而并不意味着这个对象是一个常量,任何方法可以对此变量引用的对象进行修改而不会出错
4. 静态域与静态方法:
●静态域:
将域定义为static,那么每个类中只有一个这样的域,而每一个对象对于所有的实例却都有自己的一份拷贝.
●常量:
静态常量 public static final double PI = 3.14……
共有常量是允许的
●静态方法: 不能像对象实施操作的方法
静态方法是没有this参数的方法
不能在静态方法中访问实例域,但静态方法可以访问自身类中的静态域
使用静态方法的两种状态:
当一个方法不需要访问对象状态,其所需参数都是通过显示参数提供的
当一个方法之需要访问类的静态域
静态方法的典型用途:factory方法 工厂模式(单子模式)
5. 方法参数
●
6. 对象构造
●重载:多个方法,名字相同,参数不同(只考虑参数个数和参数类型)
通过各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配来挑选出正确的方法
Java允许重载任何方法,不仅仅是构造器方法
返回类型不是方法签名的一部分,所以不能有两个名字相同,参数类型也相同但返回不同类型值得方法
●默认域初始化
如果不明确的对域进行初始化,就会影响程序代码的可读性
●默认构造器:没有参数的构造器
如果在编写一个类时没有编写构造器,系统就会提供一个默认的构造器
如果类中提供了至少一个构造器,但是没有提供默认的构造器,那么在构造对象时若不提供参数将视为不合法
●显示域初始化
●调用另一个构造器
如果构造器第一个语句如this(…),那么这个构造器将调用另一个类的另一个构造器,this()括号中的参数和参数类型将定位到哪一个构造器
●初始化块
Java的三种初始化数据的方法:
构造器
声明中赋值
初始化块
初始化块在调用构造器之前调用
调用构造器的具体处理步骤:
所有属性被初始化为默认值
按照在类声明中出现的次序依次执行所有域初始化语句和初始化块
如果在构造器中的第一行调用了第二个构造器,则执行第二个构造器主体
执行这个构造器主体
静态初始化块:在类第一次加载的时候,将会进行静态域的初始化
静态初始化块和初始化块的区别:
静态初始化块是在文件加载时执行,所以仅执行一次
初始化块是在类的构造器被调用时,调用构造器方法之前执行,可以执行多次
7. 包
●类的导入:
两种导入类的方式:
在每个类名之前添加完整的包名
使用import语句
Import语句应该位于源文件的顶部
●静态导入
实际应用:
算数函数:
笨重的常量:
●虚拟机如何定位类
能够使程序共享包,需要做到:
把类放到一个或多个指定的目录中,这个目录是包树状结构的基目录
设置类路径:所有基目录的集合,基目录中的子目录可以用于包含类文件。为编译器或解释器指定-classpath选项,或者设置CLASSPATH环境变量
类路径中的不同项目之间采用冒号(linux),分号(windows)分隔
句点表示当前目录
●包作用域
默认域:如果没有指定public或private,那么这部分可以被同一个包中的所有方法访问
对于类来说,这种默认是合乎情理的,但是对于变量来说不行
8. 文档注释:
文档注释与源代码在同一个文件中,修改源代码的同时,重新运行javadoc就可以轻而易举的保持两者的一致性
●注释的插入
需要注释的部分:
包
公有类与接口
公有的和受保护的方法
共有的和受保护的域
注意:私有的域,方法不要使用注释,要隐藏其实现,达到封装的效果
注释应该放在所描述特性的前面,注释以/**开始,以*/结束
第一句应该是一个概要性的句子,javadoc自动地将这些句子抽出来形成概要页。可以使用html标签
如果文档中有其他文件的链接,那么应该把这些文件放到子目录doc-files中,javadoc实用程序将从源目录拷贝这些目录及其中的文件到目录中
●类注释
类注释必须放在import语句之后,类定义之前。
●方法注释
方法注释必须放置在所描述的方法之前
@param
@author
@return
@throw
●域注释
只需要对公有域建立文档
●通用注释
@author
@version
@since
@deprecated 对类、方法或者变量添加一个不再使用的注释
9. 类设计技巧
●将数据设计为私有,保持封装性
●一定要对数据进行初始化
●不要在类中使用过多的基本数据类型:用其它的类代替多个相关的基本数据类型使用
●不是所有的域都需要独立的域访问器和域更改器
●使用标准格式进行类的定义
类书写内容的顺序:
共有访问特性部分
保护访问特性部分
私有访问特性部分
●将职责过多的类进行分解: 如果可以将一个复杂的类分成两个部分,就应该将其分解
●类名和方法名要能够体现他们的职责