面向对象程序设计概述
- OOP:面向对象程序设计
4.1.1 类
- 创建类的实例:由类构造对象的过程
- 封装:将数据和行为组合在一个包中,并对对象的使用者隐藏具体的实现方式。数据称为实例字段,过程成为方法。
- 类的实例特定对象有一组特定的实例字段值,这些值的集合是该对象的当前状态。
- 实现封装:不让类中的方法直接访问其他类的实例字段,程序只通过对象的方法与对象数据交互。
- 继承:扩展一个类来建立另外一个类。扩展后的新类具有被扩展的类的全部属性和方法。
4.1.2 对象
- 对象
- 行为:对对象的操作或方法
- 状态:调用方法时对象如何响应
- 标识:如何区分具有相同行为和状态的不同对象
- 对象状态的改变必须通过调用方法实现
4.1.4 类之间的关系
- 依赖:A类的方法使用或操纵B类的对象,则说A类依赖于B类(最小依赖原则)
- 聚合:A类的对象包含B类的对象
- 继承:一个更特殊的类与一个更一般的类之间的关系
使用预定义类
4.2.1 对象与对象变量
-
使用构造器来构造一个类。类的构造器的名字与类名相同,使用new操作符来构造一个新的对象
-
将new操作符构造的对象赋值给一个变量,代表此变量的值是对该对象的引用(new操作符的返回值是一个引用)
Date deadline; Date birthday = new Date(); deadline = birthday;//这两个变量指向了相同的对象
-
所有的java对象都存储在堆中,内存管理与垃圾回收自动完成
4.2.3 更改器方法与访问器方法
- 更改器:调用该方法会修改对象的状态
- 访问器:调用该方法只访问对象而不修改对象
用户自定义类
4.3.1 Employee类
- 文件名必须与public类的名字相匹配。一个源文件中只能有一个公共类。
4.3.3 剖析Employee类
- 实例字段应标记为private
4.3.4 从构造器开始
- 构造器与类同名,new运算符会调用构造器。无法重新对已存在的对象调用构造器来设置实例字段。
- 构造器可以有多个
- 构造器可以有任意数目的参数
- 构造器没有返回值。
- 不要在构造器中定义与实例字段同名的局部变量(会遮蔽同名的实例字段)
4.3.5 用var声明局部变量(Java10)
- 如果可以从变量的初始值推导出他们的类型,则可以用var来声明局部变量
- var只能用于方法重点额局部变量
4.3.6 使用null引用
-
当对象变量没有指向任何对象时,对该变量调用方法会产生NullPointerException异常
-
为了在调用构造器时解决实参可能为null的问题,可以使用如下的方法(Java9)
name = Objects.requireNonNullElse(n,"Unknown"); name = Objects.requireNonNull(n,"Cannot be null");
4.3.7 隐式参数与显式参数
- 隐式参数:对象本身
- 显式参数:方法的形参
- 在方法中最好使用this指示对象本身(隐式参数)。
4.3.8 封装的优点
- 为了不破坏封装,在类中,要获得或设置实例字段的值,需要提供下面的内容
- 一个私有的数据字段
- 一个公共的字段访问器方法
- 一个公共的字段更改器方法
- 不要编写返回可变对象引用的访问器方法
- 需要返回一个可变对象的引用,应该返回一个克隆对象(返回一个可变数据字段的副本)
4.3.9 基于类的访问权限
- 类的方法可以访问任何是该类对象的私有字段
4.3.11 final实例字段
- 将实例字段定义为final,意为该字段必须在构造对象时初始化,且不会再被修改
- 注意,若该实例字段是某对象的引用,且该对象是可变类,则final修饰符只代表该对象引用不会再指示一个别的对象,但该对象可以更改
静态字段与静态方法
4.4.1 静态字段
- 定义为static的字段为该类的所有对象共享(静态变量)
4.4.2 静态常量
- 使用static和final定义的字段是公共字段,且为常量无法被修改
4.4.3 静态方法
-
不在对象上执行的方法-不使用任何对象-没有隐式参数
-
静态方法没有this参数,故不能访问非静态的实例字段
class Employee1 { private String name; private double salary; private LocalDate hireDay; private static int nextId; public static void getNextId() { return hireDay;//报错! return nextId; } }
-
使用类名而不是对象来调用静态方法,因为静态方法与对象毫无关系
-
使用静态方法的两种情况
- 方法不需要访问对象状态
- 方法只需要访问静态字段
4.4.4 工厂方法
- 使用静态工厂方法来构造对象
- 构造器的名字与类名相同,但此时希望有两个不同的名字
- 构造器无法改变所构造的类型,工厂方法希望返回该类的子类对象
4.4.5 main方法
- 每个类都可以有一个main方法,独立测试某类时执行该方法
方法参数
- 两种引用方式
- 按值调用:方法接收调用者提供的值
- 按引用调用:方法接收调用者提供的变量地址
- Java总是采用按值调用,即,方法得到的是参数值的副本,方法不能修改传递给他的参数变量的内容
- 两种类型的方法参数
- 基本数据类型:一个方法不可能修改基本数据类型的参数
- 对象引用:对象引用作为参数时,方法得到的是对象引用的副本,故二者指向同一个对象,所以可以改变该对象参数状态
- 由于Java总是采用按值调用,同样,对象引用也是按值传递的,方法得到的是对象引用的副本
- 所以方法不能让一个对象参数引用一个新的对象
对象构造
4.6.1 重载
- 重载:两个方法具有相同的名字和不同的参数。
- 编译器会挑出具体调用什么方法,按照方法首部的参数类型与方法调用中所使用的的值类型进行匹配,这个过程叫做重载解析
- 方法的签名包括方法名和参数类型而不包括返回类型,故不能有两个名字和参数类型相同却有不同返回类型的方法
4.6.2 默认字段初始化
- 构造器中没有显示设置初值的字段会被赋为默认值
- 方法中的局部变量必须被明确的初始化,而在类中没有被初始化的字段会被自动初始化为默认值
4.6.3 无参数的构造器
- 仅当类没有任何构造器时,会得到一个默认的无参数构造器,这个构造器将把所有的实例字段设置为默认值
- 当然,也可以自己实现一个无参数构造器来初始化对象中给的实例字段
4.6.4 显式字段初始化
- 在类定义中可以直接为任何字段赋值,在执行构造器前会先完成这个赋值操作
- 也可以调用方法来初始化一个字段。
4.6.6 调用另一个构造器
- 如果构造器的第一个语句形如this(),该构造器将调用同一个类的另一个构造器
- 公共的构造器代码只需要编写一次。
4.6.7 初始化块
- 三种初始化数据字段的方法
- 在构造器中设置值
- 在声明中赋值
- 在声明中包含任意多个代码块。在构造这个类的对象时,这些块将会被执行。
- 首先运行初始化块,然后才运行构造器的主体部分
- 调用构造器的具体步骤
- 如果构造器的第一行调用了另一个构造器,则基于所提供的参数执行第二个构造器
- 否则
- 所有数据字段初始化为其默认值(0、false或null)
- 按照在类声明中出现的顺序,执行所有字段初始化方法和初始化块
- 执行构造器主体代码
- 静态字段可以使用静态的初始化块
包
4.7.1 包名
- 域名逆序作为包名,再加上工程名。
- 从编译器角度看,嵌套的包没有任何关系
4.7.2 类的导入
- 一个类可以是用所属包中的所有类和其他包中的公共类
4.7.3 静态导入
- 使用带static关键字的import语句来导入静态方法和静态字段,而不只是类
文档注释
4.9.1 注释的插入
- 注释以/**开始,*/结束每个注释包含标记及之后紧跟的自由格式文本,标记以@开始,自由格式文本的第一句是一个概要性的句子。自由格式文本可以使用html修饰符
4.9.3 方法注释
- @param:给当前方法的参数部分添加一个条目
- @return: 给当前方法添加返回部分
- @throws:表示这个方法可能抛出异常
4.9.4 通用注释
- @since:建立一个“since”条目
- @author:建立一个作者条目,可以使用多个
- @version:产生一个版本条目
- @see和@link标记可以使用超链接
- @see的reference有以下选择
- package.class#feature label
- <a href=“…”>label</a>
- text
- @see的reference有以下选择
4.9.6 包注释
- 提供package-info.java的java文件
- 提供package.html的html文件
4.10 类设计技巧
- 保证数据私有
- 对数据进行私有化
- 不要使用过多的基本类型
- 不是所有的字段都需要单独的访问器和更改器
- 分解有过多指责的类
- 类名和方法名要能够体现它们的指责
- 类名应当是一个名词,或有形容词修饰的名词,或动名词
- 访问器用get开头,更改器用set开头
- 优先使用不可变的类