文章目录
一 : 面向对象程序设计概述
1.1 类
- 类(class) 是构造对象的模板或蓝图。我们可以将类想象成制作小甜饼的切割机,将对象想象为小甜饼
- 由类构造(construct) 对象的过程称为创建类的实例 (instance).
封装(encapsulation, 有时称为数据隐藏)是与对象有关的一个重要概念。从形式上看, 封装不过是将数据和行为组合在一个包中, 并对对象的使用者隐藏了数据的实现方式。对象 中的数据称为实例域( instance field), 操纵数据的过程称为方法(method )。对于每个特定的 类实例(对象)都有一组特定的实例域值。这些值的集合就是这个对象的当前状态(state)。 无论何时,只要向对象发送一个消息,它的状态就有可能发生改变。
实现封装的关键在于绝对不能让类中的方法直接地访问其他类的实例域。程序仅通过对 象的方法与对象数据进行交互。封装给对象赋予了“ 黑盒” 特征, 这是提高重用性和可靠性 的关键。 这意味着一个类可以全面地改变存储数据的方式,只要仍旧使用同样的方法操作数据, 其他对象就不会知道或介意所发生的变化。
- 通过扩展一个类来建立另外一个 类的过程称为继承(inheritance).
1.2 对 象
- 要想使用 OOP, —定要清楚对象的三个主要特性:
- 对象的行为(behavior)— —可以对对象施加哪些操作,或可以对对象施加哪些方法?
- 对象的状态(state)— —当施加那些方法时,对象如何响应?
- 对象标识(identity)— —如何辨别具有相同行为与状态的不同对象?
同一个类的所有对象实例, 由于支持相同的行为而具有家族式的相似性。对象的行为是 用可调用的方法定义的。
此外,每个对象都保存着描述当前特征的信息。这就是对象的状态。对象的状态可能会 随着时间而发生改变,但这种改变不会是自发的。对象状态的改变必须通过调用方法实现 (如果不经过方法调用就可以改变对象状态,只能说明封装性遭到了破坏)。
但是,对象的状态并不能完全描述一个对象。每个对象都有一个唯一的身份(identity)。例 如,在一个订单处理系统中,任何两个订单都存在着不同之处’ 即使所订购的货物完全相同也是 如此。需要注意’ 作为一个类的实例,每个对象的标识永远是不同的,状态常常也存在着差异。
1.3 类之间的关系(重点)
在类之间, 最常见的关系有
- 依赖( “ uses-a”)
- 聚合( “ has-a”)
- 继承( “ is-a”)
依赖(dependence), 即“ uses-a” 关系, 是一种最明显的、最常见的关系。例如,Order 类使用 Account 类是因为 Order 对象需要访问 Account 对象查看信用状态。但是 Item类不依 赖于 Account 类, 这是因为 Item 对象与客户账户无关。因此, 如果一个类的方法操纵另一个 类的对象,我们就说一个类依赖于另一个类。
应该尽可能地将相互依赖的类减至最少。如果类 A 不知道 B 的存在, 它就不会关心 B 的任何改变(这意味着 B 的改变不会导致 A 产生任何bug)。用软件工程的术语来说,就是 让类之间的耦合度最小。
聚合(aggregation), 即“ has-a” 关系, 是一种具体且易于理解的关系。例如, 一个 Order 对象包含一些Item 对象。聚合关系意味着类 A 的对象包含类 B 的对象。
继承(inheritance), 即“ is-a” 关系, 是一种用于表示特殊与一般关系的。例如,Rush Ordei类由 Order 类继承而来。在具有特殊性的 RushOrder类中包含了一些用于优先处理的特殊方法,以及一个计算运费的不同方法;而其他的方法, 如添加商品、生成账单等都是从 Order类继承来的。一般而言, 如果类 A 扩展类 B, 类 A 不但包含从类 B 继承的方法,还会 拥有一些额外的功能
二 : 使用预定义类
2.1 对象与对象变量
- 在对象与对象变量之间存在着一个重要的区别
Date deadline; // deadline doesn't refer to any object
- 定义了一个对象变量 deadline, 它可以引用 Date 类型的对象。但是,一定要认识到: 变量 deadline 不是一个对象, 实际上也没有引用对象。此时,不能将任何 Date 方法应用于这个变 量上。
- 一定要认识到: 一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。
- 在 Java 中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。
2.2 Java 类库中的 LocalDate 类
- 标准 Java 类库分别包含了两个类: 一个是用来表示时间点的 Date 类;另一个是用来表示大家熟悉的日历表示法的 LocalDate 类。
- 不要使用构造器来构造 LocalDate类的对象。实际上,应当使用静态工厂方法 (factory method) 代表你调用构造器
LocalDate.now();
更改器方法 : 调用这个方法后, 对象的状态会改变
访问器方法: 只访问对象而不更改对象状态的方法.
- 显示当前月的日历
public static void main(String[] args) throws IOException {
LocalDate date = LocalDate.now();
int month = date.getMonthValue();//获取月份
int today = date.getDayOfMonth();// 获取天数
// 2009-01-01减去一天将导致2008-12-31。
// 可以为负数,为负数则加天数
date = date.minusDays(today - 1); // 减去指定的天数,
DayOfWeek dayOfWeek = date.getDayOfWeek();// 得到这一天为星期几
int value = dayOfWeek.getValue(); // 转换为整数
// 打印表头和第一行的缩进
System.out.println("Mon Tue Wed Thu Fri Sat Sun");
for (int i = 0; i < value; i++) {
System.out.print(" ");
}
// 打印主体
while (date.getMonthValue() == month) { //判断是否是本月的天数
System.out.printf("%2d", date.getDayOfMonth());
if (date.getDayOfMonth() == today) {
System.out.print("* ");
} else {
System.out.print(" ");
}
date = date.plusDays(1);// 加一天
if (date.getDayOfWeek().getValue() == 1) { //判断下一天是否是周一
System.out.println();
}
if (date.getMonthValue() != 1) {
System.out.println();
}
}
}
API:java.time.LocalDate 8
- static LocalTime now( )
构造一个表示当前日期的对象。 - static LocalTime of(int year, int month, int day)
构造一个表示给定日期的对象。 - int getYear( )
- int getMonthValue( )
- int getDayOfMonth( )
得到当前日期的年、 月和曰。 - DayOfWeek getDayOfWeek()
得到当前日期是星期几, 作为 DayOfWeek 类的一个实例返回。调用 getValue 来得到 1 ~ 7 之间的一个数, 表示这是星期几, 1 表示星期一, 7 表示星期日。 - LocalDate piusDays(int n)
- LocalDate minusDays(int n)
生成当前日期之后或之前 n 天的日期。
三 : 用户自定义类
3.1 构造器
- 构造器 :
- 构造器与类同名
- 每个类可以有一个以上的构造器
- 构造器可以有 0 个、1 个或多个参数
- 构造器没有返回值
- 构造器总是伴随着 new 操作一起调用
3.2 隐式参数与显式参数 (重点)
- 方法用于操作对象以及存取它们的实例域 例如,方法:
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
- 将调用这个方法的对象的 salary 实例域设置为新值。看看下面这个调用:
number007.raiseSalary(5);
- 它的结果将 number007.salary 域的值增加 5%。具体地说,这个调用将执行下列指令:
double raise = nuaber007.salary * 5 / 100;
nuiber007.salary += raise;
raiseSalary方法有两个参数。 第一个参数称为隐式( implicit) 参数, 是出现在方法名前的 Employee 类对象。第二个参数位于方法名后面括号中的数值,这是一个显式( explicit) 参 数 (有些人把隐式参数称为方法调用的目标或接收者)
- 可以看到,显式参数是明显地列在方法声明中的, 例如 double byPercent。隐式参数没有 出现在方法声明中。
- 在每一个方法中, 关键字 this 表示隐式参数。 如果需要的话,可以用下列方式编写 raiseSalary 方法:
public void raiseSalary(double byPercent) {
double raise = this.salary * byPercent / 100;
this.salary += raise;
}
3.3 final 实例域
- 可以将实例域定义为 final。 构建对象时必须初始化这样的域.
- 定义为 final的实例域不能再被修改.
四: 静态域与静态方法
4.1 静态域
- 如果将域定义为 static, 每个类中只有一个这样的域。而每一个对象对于所有的实例域 却都有自己的一份拷贝。
class Employee {
private static int nextld = 1 ;
private int id;
}
- 每一个雇员对象都有一个自己的 id 域, 但这个类的所有实例将共享一个 nextld 域。换句话说, 如果有 1000 个 Employee类的对象, 则有 1000 个实例域 id。但是,只有一 个静态域 nextld。即使没有一个雇员对象, 静态域 nextld 也存在。它属于类,而不属于任何 独立的对象。
4.2 静态方法
- 被static修饰的方法.
- 静态方法是一种不能向对象实施操作的方法。
- 可以认为静态方法是没有this参数的方法.
- 调用静态方法要使用类名调用.
- 在下面两种情况下使用静态方法:
- 一 个方法不需要访问对象状态,其所需参数都是通过显式参数提供(例 如: Math.pow)
- 一个方法只需要访问类的静态域(例如:Employee.getNextldh)
4.3 工厂方法
- 静态方法还有另外一种常见的用途。类似 LocalDate 和 NumberFormat 的类使用静态工 厂方法 (factory method) 来构造对象。
- 例如 : LocalDate.now
4.4 main方法
- main方法也是一个静态方法.
- main方法不对任何对象进行操作。事实上,在启动程序时还没有任何一个对象。静态的 main方法将执行并创建程序所需要的对象。
- 每一个类可以有一个main方法.