Java核心技术-对象与类
1 面向对象程序设计概述
面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。
1.1 类
类是构造对象的模板或蓝图,由类构造对象的过程称为创建类的实例。
封装:
从形式上看,是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。
对象中的数据称为实例域,操纵数据的过程称为方法。
对于每个特定类实例(对象)都有一组特定的实例域值,这些值的集合就是这个对象的当前状态。
实现封装的关键在于绝对不能让类中的方法直接地访问其它类的实例域,程序仅能通过对象的方法与对象数据进行交互。
在Java中,所有类都源于一个“神通广大的超类”,它就是Object。
通过扩展一个类来建立另一个类的过程称为继承。
1.2 对象
对象的三个主要特性:
对象的行为——可以对对象施加哪些操作,或可以对对象施加哪些方法。
对象的状态——当施加那些方法时,对象如何响应。
对象的标识——如何辨别具有相同行为与状态的不同对象。
1.3 识别类
识别类的简单规则是在分析问题的过程中寻找名词,而方法对应着动词。
1.4 类之间的关系
在类之间,最常见的关系有
*依赖(“uses-a"):一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。减少依赖即减少耦合。
*聚合("has-a"):类A的对象包含类B的对象。
*继承(”is-a"):用于表示特殊与一般关系的。
2 使用预定义类
2.1 对象与对象变量
要想使用对象,就必须首先构造对象,并指定其初始状态。构造器是一种特殊的方法,用来构造并初始化对象。
构造器的名字应该与类名相同。
明白对象与对象变量之间的区别。
一定要认识到:一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。任何对象变量的值都是对存储在另外一个地方的一个对象的引用。
局部变量不会自动初始化为null,而必须通过调用new或将他们设置为null进行初始化。
2.2 LocalDate类
Java中,Date类用来表示时间点,LocalDate类用来表示日历表示法。
不要使用构造器来构造LocalDate类,应该使用静态工厂方法代表你调用构造器:LocalDate.now()会构造一个表示构造这个对象时的日期对象。
2.3 更改器方法与访问器方法
类似于String类的toUpperCase方法,调用这个方法时原对象不变,会返回一个将原对象中所有字符大写的新对象。
相比较而言,那些会更改原对象状态的方法称为更改器方法。(GregorianCalendar.add)
访问器方法:只访问对象而不修改对象的方法。
3.用户自定义类
实例域(private)+实例方法
3.1 构造器
*构造器与类同名
*每个类可以有一个以上的构造器
*构造器可以有0、1个或多个参数
*构造器没有返回值
*构造器总是伴随着new操作一起调用
3.2 隐式参数与显示参数
一般方法有两种参数,第一种参数称为隐式参数,出现在方法名前的类对象。第二种显示参数是位于方法名后面括号中的数值。
在每一个方法中,关键字this表示隐式参数。
3.3 封装的优点
*一个私有的数据域
*一个公有的域访问器方法
*一个公有的域更改器方法
注意不要编写返回引用可变对象的访问器方法,如果需要返回一个可变对象的引用,应该首先对它进行克隆。
public Date getHireDay(){
return (Date)hireDay.clone();
}
3.4 基于类的访问权限
一个方法可以访问所属类的所有对象的私有域数据。
3.5 final实例域
final修饰符大都应用于基本类型域,或不可变类的域。
对于可变的类,final关键字只表示存储在可变类对象中的对象引用不会再指向其它类对象,不过这个对象仍可以更改。(StringBuilder)
4 静态域与静态方法
4.1 静态域(类域)
如果将域定义为static,那么每个类中只有一个这样的域。即使没有一个类对象存在,静态域也存在。它属于类,而不属于任何独立的对象。
4.2 静态常量
Math.PI、System.out
公有常量只能访问不能修改:public final
system类有一个setOut方法看,可以将System.out(final变量)设置为不同的流,因为setOut方法是一个本地方法,不是用Java语言实现的,可以绕开Java语言的存取控制机制。
4.3 静态方法
静态方法是一种不能向对象实施操作的方法。
静态方法不能访问类的实例域,但是可以访问自身类中的静态域。
使用静态方法的两种情况:
* 一个方法不需要访问对象状态,其所需的参数都是通过显示参数提供(Math.pow)
* 一个方法只需要访问类的静态域
4.4 工厂方法
静态方法还有另一种常见的用途:静态工厂方法——不通过 new
,而是用一个静态方法来对外提供自身实例的方法
静态工厂构造对象和构造器构造对象的主要区别(更灵活):
1.可以命名构造器名称
2.不用每次被调用时都创建新对象
3.可以返回原返回类型的子类
5 方法参数
参数传递给方法的两种方式:按值调用和按引用调用。
一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
Java采用按值调用。
方法参数两种类型:
*基本数据类型
*对象引用
Java中方法参数的使用情况:
*一个方法不能修改一个基本数据类型的参数
*一个方法可以改变一个对象参数的状态
*一个方法不能让对象参数引用一个新的对象
6 对象构造
6.1 重载
由编译器进行重载解析。
方法签名:要完整地描述一个方法,需要指出方法名以及参数类型。(返回类型不是方法签名的一部分)
6.2 默认域初始化
如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值:数值为0、布尔值为false、对象引用为null。
这是域与局部变量的主要不同点——局部变量没有默认初始化,必须显示的初始化局部变量。
6.3 无参数构造器
如果类中提供了至少一个构造器,但是没有提供无参数的构造器,则在构造对象时没有提供参数就会被认为不合法。
仅当类中没有提供任何构造器,系统才会提供一个默认构造器。
6.4 调用另一个构造器
如果构造器的第一个语句形如this(),这个构造器将调用同一个类的另一个构造器。
6.5 初始化块
初始化数据域的方法:
1.在构造器中设置值
2.在声明中赋值
3.初始化块
调用构造器初始化的步骤:
所有数据域被初始化为默认值(静态域初始化)->数据域初始化语句->初始化块->构造器
6.6 对象析构器与finalize方法
finalize方法将在垃圾回收器清除对象之前调用。
如果某个资源需要在使用完毕后立刻关闭,可以应用一个close方法来完成相应的清理操作。
7 包
使用包的主要原因是确保类名的唯一性。
7.1 类的导入
一个类可以使用所属包中的所有类,以及其它包中的公有类。
只能使用星号(*)导入一个包,而不能使用import java.*或import java.*.*导入以java为前缀的所有包。
可以采用增加一个特定的包名解决两个包中共有类的引用问题。
如果两个包中的两个相同名称的类都要引用,可以在每个类名前加上完整的包名。
7.2 静态导入
import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。
7.3 将类放入包中
编译器对文件(带有文件分隔符和扩展名.java的文件)进行操作。而Java解释器加载类(带有.分隔符)
7.4 包作用域
标记为public的部分可以被任意的类使用;标记为private的部分只能被定义它们的类使用。如果没有指定public或private,这个部分(类、方法、变量)可以被同一个包中的所有方法访问。
8 类设计技巧
1.一定要保证数据私有
2.一定要对数据初始化
3.不要在类中使用过多的基本类型
4.不是所有的域都需要独立的域访问器和域更改器
5.将职责过多的类进行分解
6.类名和方法名要能体现它们的职责
7.优先使用不可变的类(考虑具体情况)