一、对象和类
每个对象包含对用户公开的特定功能部分和隐藏的实现部分
类是构造对象的模板或蓝图
对象的特性
- 对象的行为:可以对对象施加哪些操作或可以对对象施加哪些方法?
- 对象的状态:当施加方法的时候对象如何响应?
- 对象的标识:如何辨别具有相同行为和状态的不同对象?
类之间的关系
- 依赖(use a):一个类的方法操纵另一个类的对象
- 聚合(has a):一个订单order对象包含一些物品item对象
- 继承(is a):用于表示特殊与一般关系
二、对象和类的创建
构造器
- 构造器与类同名
- 每个类可以有一个以上的构造器
- 构造器可以有多个参数
- 构造器没有返回值
- 构造器总是伴随着new操作一起调用
显式和隐式参数
- 显式参数:明显地列在方法声明中,即percent
- 隐式参数:没有出现在方法声明中,即salary,可以使用this表示它是隐式的参数(重名?)
public void raiseSalary(double percent){
double raise = salary*percent/100;
salary+=raise;
}
封装
- 有时称为数据隐藏,实现封装的关键是绝对不能让类中的方法直接地访问其他类的实例域,程序仅仅通过对象的方法和对象数据交互。
- 注意不要编写返回引用可变对象的访问器方法!
- 如果需要返回一个可变对象的引用,应该首先对他进行克隆。
class Employee{
public Date getHireDay(){
return (Date)hireDay.clone(); //Ok
}
}
三、静态域和方法
静态域
- 如果将id域定义为static,那么这个类的所有实例将共享一个id域。换句话说,如果有1000个对象,只有一个id域。
- 即使没有一个对象,静态域也存在。它属于类而不属于任何独立的对象。
静态方法
- 静态方法是一种不能向对象实施操作的方法。但是静态方法可以访问自身类中的静态域
- 当一个方法不需要访问对象状态,其所需的参数都是通过显式参数提供时要使用静态方法。(Math.pow)
- 当一个方法只需要访问类的静态域(获取id)
方法参数
- 按值调用表示方法接受的是调用者提供的值,按引用调用表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
- 对象引用是按值传递的
- 一个方法不能修改一个基本类型的参数(即数值型或布尔型)
- 一个方法可以改变一个对象参数的状态
- 一个方法不能让对象参数引用一个新的对象
域初始化
- 构造器中设置值
- 在声明中赋值
- 初始化块(block):只要构造类的对象,这些块就会被执行
public class Employee {
private static int nextid;
private int id = assignId(); //声明中初始化
private String name;
private double salary;
//初始化块
{
id = nextid;
nextid++;
}
//构造器初始化
public Employee(){
name = "";
salary = 0;
}
public Employee(String n,double s){
name = n;
salary = s;
}
private static int assignId(){
int r = nextid;
nextid++;
return r;
}
}
调用构造器的具体处理步骤
- 所有数据域被初始化为默认值
- 按照在类声明中出现的次序,依次执行所有域初始化语句和初始化块
- 如果构造器第一行调用了第二个构造器主体则执行第二个构造器主体
- 执行这个构造器主体
类设计
基本类设计原则
- 一定要保证数据私有,绝对不要破坏封装性
- 一定要对数据进行初始化,显式地初始化所有的数据
- 不要在类中使用过多的基本类型,即用其他的类代替多个相关的基本类型的使用
- 不是所有的域都需要独立的域访问器和域更改器,比如应该禁止更改雇员的入职日期
- 将职责过多的类进行拆分分解
- 类名和方法名应该体现他们的职责
- 优先使用不可变的类。java.time包中的一些类是不可变的——没有方法可以修改对象的状态,修改对象的方法不会更改对象而是返回一个新对象。更改对象的问题在于如果多个线程试图同时更新一个对象,就会发生并发更改,结果不可预料。如果类是不可变的就可以安全的在多个进程中共享对象。