第4章 对象与类
__4_1 概述
过程化程序设计以算法为第一位,数据结构为第二位
OOP把数据放在第一位,然后考虑操作数据的算法
1)概念
类 class
构造 construst
实例 instance
封装(数据隐藏)encapsulation
实例域 instance fields
方法 method
实例域值(状态)state
2)封装——提高重用性和可靠性的关键,一个类只要使用同样的方法操作数据,其他对象则不会知道和介意所发生的变化
3)对象的行为(behavior),状态,标识(identity),相互影响。
4)类之间的关系
a)依赖 (“use-a”) 将相互依赖的类减至最少,让类之间的耦合度最小
b)聚合 (“has-a”)
c)继承 (“is-a”)
5)对象与对象变量
Date deadline; //deadline
是一个对象变量,它不是对象,也没有引用对象。
Java中任何对象变量的值都是对存储在另外一个地方的一个对象的引用。可以显式的把它置为null,以表示没有引用任何对象。
6)更改器方法和访问器方法
对实例域做出修改的方法—— 更改器方法(mutator method)
仅访问不修改的方法—— 访问器方法(accessor method)
7)不要编写返回引用可变对象的访问器方法
class Employee
{
public Date getHireDay()
{
return hireDay;
}
private Date hireDay;
}
这样会破坏封装性。如果需要返回一个可变对象的引用,应首先对它克隆。
8)一个方法可以访问所属类的所有对象的私有数据,而不仅限于访问隐式参数私有属性。
9)当希望将一个计算代码分为若干独立的辅助方法,通常这些方法需要一个特别的协议以及一个特别的调用次序,这些辅助方法最好设计为private。
10)只要方法是私有的,类的设计者就可以确信它不会被外部的其他类操作调用,可以将其删去。
11)Final实例域
构建对象时必须初始化这样的域。
final大多应用与基本数据类型域,或不可变类的域(如果类中的每个方法都不会改变其对象,此为不可变类)。
12)静态域
静态域属于类而不属于任何独立的对象,这个类的所有实例将共享一个静态域
13)静态常量
public static final double PI = 3.14......;
14)静态方法
不能向对象实施操作的方法(计算Math.pow(x,a);时不使用任何Math对象),即没有隐式的参数。
静态方法不能操作对象,故不能在静态方法中访问实例域,但是,静态方法可以访问自身类中的静态域。
public static int getNextId()
{
return nextId;
}
int n = Employee.getNextId();
在
a)在一个方法不需要访问对象状态,其所需参数都是通过显式参数提供
b)在一个方法只需要访问类的静态域
时使用静态方法
15)Factory方法
静态方法还用一种常见的用途,NumberFormat类使用factory方法产生不同风格的格式对象。
NumberFormat currencyFomatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFomatter = NumberFormat.getPercentInstance();
double x = 0.1;
System.out.println(currencyFormatter.format(x)); //prints $0.10
System.out.println(percentFomatter.format(x)); //prints 10%
使用factory方法而非构造器的原因:
a)无法命名构造器
b)使用构造器无法改变构造的对象类型
16)Main方法
启动程序时还没有任何一个对象,静态的main方法将执行并创建程序所需要的对象。
每个类可以有一个main方法,这是单元测试的技巧。
__4_2 方法参数
Java总是采用值调用
__4_3 对象构造
1)重载与重载解析
方法的签名: 方法名+方法参数,不包括返回类型
2)默认域初始化
必须明确初始化方法中的局部变量,但是没有给域赋值时将自动赋值为默认值。
3)默认构造器
默认构造器即没有参数的构造器,仅当没有编写构造器时,系统会提供一个默认构造器,这个默认构造器将所有实例域设置为默认值。
4)显式域初始化
初始值不一定是常量,可以调用方法对域进行初始化。
Class Employee
{
static int assignId() //去掉static 也可以
{
int r = nextId;
nextId++;
return r;
}
...
private int id = assignId();
}
5)参数名
使用同样的名字屏蔽实例域;
public Employee(String name)
{
this.name = name;
}
6)调用另一个构造器
在此构造器第一个语句调用
this(...);
7)初始化块
在一个类的声明中可以包含多个代码块,只要构造类的对象,这些块就会被执行。
class Employee
{
//methods
...
//fileds
...
//object initialization block
{
id = nextId;
nextId ++;
}
}
对静态域进行初始化时可以使用静态的初始化
static //此static标签去掉后每次实例化将都执行这一代码块,否则只执行一次
{
Random generator = new Random();
nextId = generator.nextInt(10000);
}
8)对象析构
…
__4_4 包
所有标准的java包都处于java和javax包层次中。嵌套的包之间没有任何关系,如java.util包与java.util.jar包。
1)类的导入
一个类可以使用所属包中的所有类以及其他包中的公有类。使用import语句导入特定的类或整个包,以使用Date的简写代替java.util.Date。import语句位于源文件顶部,package语句之后。相比import java.util.Date,import java.util.* 更简单,且对代码的大小没有任何负面影响 。
当util包与sql包中都有Date类,而程序只使用uitl包中的Date类时
import java.util.*;
import java.sql.*;
import java.util.Date;
若两个包都需使用,则在使用时添加完整的包名。
2)静态导入
import导入静态方法和静态域
import static java.lang.System.*; //out已为静态域,PrintStream的实例,不可导入java.lang.System.out.println();
import static java.lang.Math.sqrt; //导入静态方法
import static java.util.Calendar.*; //导入常量 MONDAY ... DAY_OF_WEEK...等
...
out.println("Goodbye,World!");
exit(0); //System.exit();
3)将类放入包中
将包的名字放在源文件的开头 package com.horstmann.corejava;
将包中的文件放到与完整包名匹配的子目录中。
4)包作用域
标记为public的部分可以被任意类使用
标记为private的部分只能被定义它们的类使用
没有指定public或private的部分可以被同一个包中的所有方法访问
__4_5 类路径
JAR文件使用ZIP格式组织文件和子目录。
__4_6 文档注释
略
__4_7 类设计技巧
1)数据设计为私有,绝对不要破坏封装性。
2)一定要对数据初始化。
3)不要在类中使用过多的基本数据类型。
4)使用标准格式进行类的定义。
5)将职责过多的类分解。
6)类名和方法名要能够体现它们的职责。