Github代码链接: https://github.com/deyou123/corejava.git

第四章对象与类

4.1 面向对象程序设计概述

4.1.1类

  • 类是构造对象的模板或蓝图
  • 由类构造对象的过程成为创建类的实例
  • 封装:将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。
  • 实例域(instance field):对象中的数据
  • 方法(method):操纵数据的过程

4.1.2对象

  • 对象的行为:对对象施加哪些操作、方法。
  • 对象的状态:当世家哪些方法时,对象如果相应。
  • 对象标识:如何辨别具有相同行为与状态的不同对象

4.13识别类

  • 首先从设计类开始,然后再往每个类中添加方法。
  • 名词-》属性; 动词-》 方法。

4.1.4类之间的关系

java核心技术卷一十二版pdf java核心技术卷一第十版_java

  • 依赖(use-a):一个类的方法操纵另一个类的对象。减少依赖(耦合度)
  • 聚合(has-a)、关联:一个对象包含一些Iten对象
  • 继承(is-a):类A扩展类B。

4.2 使用预定义类

Math类

4.2.1对象与对象变量

使用构造器构造实力

4.2.2 java类库中的LocalDate类

  • 纪元:UTC时间1970年1yue1日 00:00:00.

4.2.3更改器方法与访问器方法

static LocalTime now();
static LocalTime of(int year, int month, int day);
int getYear();
int getMonthValue();
int getDayOfMonth();
DayOfWeek getDayOfWeek(); 得到当前日期时星期几,getValue()-> 1~7
LocalDate plusDay(int n);
LocalDate minusDays(int n);:生成当前日期之后或之前n天的日期。

4.3 用户自定义类

4.3.4从构造器开始

  • 构造器与类同名
  • 每个类可以有一个以上的构造器
  • 狗在其可以有0个、或多个参数
  • 构造器没有返回值
  • 构造器总是盘随着new 操作一起调用
警告
  • 不要再构造器中定义与实例域重名的局部变量,这些变量屏蔽了同名的实例域。

4.3.6封装的优点

提供下面三项内容:

  • 一个私有的数据域
  • 一个共有的域访问器方法;
  • 一个共有的域更改其方法。

好处:

  • 可以改变内部实现,
  • 更改器方法可以执行错误检查

警告

  • 不要编写返回引用可变对象的访问器方法
  • 如果需要返回一个可变对象的引用,应该首先对他进行克隆(clone)
  • ex:
public Date getDate(){
	return (Date)hireDay.clone();
}

4.3.7 基于类的访问权限

  • 方法可以访问所调用对象的私有数据;而不仅限于访问隐士参数的私有特性。
  • ex:
public boolean equals(Employee other){
return name.equals(other.name);
//也可以访问other的私有属性。
}

4.3.8 私有方法

  • 应该经所有的数据域都设置为私有的
  • 大多数方法都被设置为共有的
  • 设置为私有的:可能希望将一个计算代码划分成如干戈独立的赋值方法,这些方法应该为私有的。
    这是由于他们往往与当前的实现机制非常紧密,或者需要一个特别的协议以及一个特别的调用次序。最好设计为private。

4.3.9 final实例域

  • final修饰符大都应用于基本类型与,或不可变类的域(如果类中的每一个方法都不会改变其对象,这种类就是不可变的类,String)
  • 只想在构造器赋值,之后不再修改的域

4.4 静态域与静态方法

4.4.1静态域

  • 将域定义为static,每个类只有一个这样的域;而每个对象对于所有的实例域却都有自己的一份拷贝。
  • 每个实例共享一个静态域

4.4.2 静态常量

  • public static final double PI = 3.14159265…
  • public static final PrintStream out = …;

4.4.3 静态方法

通过类名调用方法。

public static int getNextId(){
	return nextId;
}

int n = Class.getNextId();

下面两种情况下使用静态方法:

  • 一个方法不需要访问对象状态,其所需参数都是通过显示参数提供(ex:Math.pow)
  • 一个方法只需要访问类的静态域(Class.getNextId)

4.5 方法参数

  • 按值调用:方法接收的是调用者提供的值
  • 按引用调用:方法接收的是调用所对应的变量值
  • Java程序设计语言总是采用按值调用

方法参数的两种类型:

  • 基本数据类型(数值、布尔值)
  • 对象引用

警告

  • Java程序设计语言对对象采用的不是引用调用,对象引用是按值传递的。
总结,Java中方法参数的使用情况:
  • 一个方法不能修改一个基本数据类型的参数。
  • 一个方法可以改变一个对象参数的状态
  • 一个方法不能让对象参数引用一个新的对象

4.6 对象构造

4.6.1 重载

  • 重载:多个方法,有相同的名字、不同的参数,便产生了重载。
  • 重载解析:编译器通过哥哥方法给出的参数类型与特性方法调用所使用的值类型进行匹配来挑选出相应的方法。编译器找不到匹配的参数就产生编译时错误。
  • Java允许重载任何方法,不只是构造器方法。
  • 方法的签名:方法名和参数类型。
  • 返回类型不是方法签名的一部分;不能由两个名字相同、参数类型也相同,但返回不同类型值的方法。

4.6.2 默认域初始化

  • 如果构造器没有显示的给域赋予初值,就会被自动的赋为默认值。
  • 数值:0; 布尔值:false; 对象引用:null
  • 我们不希望得到一个null引用

4.6.3无参数构造器

  • 构造器将所有的实例域设置为默认值。
  • 仅当类没有提供任何构造器的时候,系统才会提供一个默认的构造器。

4.6.4 显式域初始化

  • 通过重载类的构造器方法,可以次啊用多种形式设置类的实例域的初始状态。
  • 在执行构造器之前,先执行赋值操作(调用方法对域进行初始化)

什么时候用:

  • 当一个类的所有构造器都希望把相同的值赋予某个特定的实例域时
  • 初始值不一定是常量值。

4.6.5 参数名

  • 参数变量用同样的名字将实例域屏蔽起来。
  • 采用 this.xxx

4.6.6 调用另一个构造器

  • 关键字this引用方法的隐式参数。
  • 形如 this(…),这个构造器将调用同一个类的另一个构造器。
public Employee(double s){
	this("Employee #" + nextId, s);
	nextId++;
}
  • 对公共的构造器代码部分只编写一次即可。

4.6.7 初始化块

  • 首先运行初始化块,然后才运行构造器的主体部分。
  • 不是必须,也不常见。
初始化数据与的方法
  • 在构造器中设置值
  • 在声明中赋值
  • 在代码块中赋值
...
{
id = xxx;
}
...
调用构造器的具体处理步骤:

1)所有数据域被初始化为默认值(0、false、null)
2)按照在类声明中出现的次序,依次执行所有域初始化语句和初始化块。
3)如果构造器第一行调用了第二个构造器,则执行第二个构造器主体。
4)执行当前构造器主体。

  • 如果对类的静态域进行初始化的代码比较复杂,那么可以使用静态的初始化块。
  • 在类第一次加载的时候,将会进行静态域的初始化。
static{
Random generator = new Ramdom();
nextId = generator.nextInt(1000);
}

4.6.8 对象析构与finalize方法

  • 在析构器中,最常见的操作时回收分配给对象的存储空间。
  • Java不支持析构器,Java由自动的垃圾回收器。
  • 某些情况,使用了内存之外的其他资源(文件或系统资源的另一个对象的句柄)
  • finalize方法在垃圾回收器清楚对象之前调用;实际很难知道这个方法什么时候才能够调用。

  • System.runFinalizersOnExit(true);
  • Runtime.addShutdownHook

4.7 包

  • 使用包的主要原因是 确保类名的唯一性。
  • 为了保证包名的绝对唯一型,Sun公司建议将公司的因特网域名以逆序的形式作为包名:com.horstmann.corejava

4.7.1 类的导入

  • 一个类可以使用所属包中的所有类,以及其他包中的共有类

两种方式访问另一个包中的公有类:

  • 在每个类名之前添加完成的包名:
    java.time.LocalDate today = java.time.LocalDate.now();
  • 使用import语句导入一个特定的类或者整个包。import语句位于源文件的顶部

注意:

  • 只能使用星号(*)导入一个包。
  • 不能使用 import java.* 或者 import java.*.*导入以java为前缀的所有包

发生命名冲突时

  • 采用一个特定的import语句。
    import java.util.Date, 定位到冲突的类
  • 类名前加上完整的包名
    java.util.Date deadline = new java.util.Date();
    java.sql.Date today = new java.sql.Date();

4.7.2 静态导入

  • 导入静态方法和静态域
    import static java.lang.System.*;
    就可以不加类名前缀,使用System类的静态方法和静态域。
    out.println(“xxx”);
    exit(0);
  • 导入特定的方法或域
    import static java.lang.System.out;

4.7.3 将类放入包中

  • 要想将一个类放入包中,就必须将包的名字防砸i源文件的开头,包中定义类的代码之前。
  • 默认包是一个没有名字的包

4.7.4 包作用域

4.8 类路径

4.9 文档注释

4.9.1 注释的插入

javadoc从下面几个特性中抽取信息:

  • 共有类与接口
  • 共有的和受保护的构造器及方法
  • 共有的和受保护的域

格式:以/**…*/文档注释,在标记之后紧跟自由格式文本。
标记由@开始。
自由格式文本中,可以使用HTML修饰符

4.9.2 类注释

  • 放在import语句之后,类定义之前

4.9.3 方法注释

  • @param 变量描述,可占据多行,并可以使用HTML标记
  • @return
  • @throws

4.9.4 域注释

  • 只需要对共有域建立文档

4.9.5 通用注释

  • @author 姓名
  • @version 文本
  • @since 文本: 可以是对引入特性的版本描述
  • @deprecated 文本:对类、方法或变量添加一个不再使用的注释
@deprecated Use <code> setVisible(true) </code> instead
  • @see 引用:增加一个超链接
  • @see com.horstmann.corejava.Employee#raiseSalary(double)
    建立一个连接到com.horstmann.corejava.Employee类的raiseSalary(double)
    +@see < a href=“www.horsetmann.com/corejava.html”> text

4.10 类设计技巧

  • 1、一定要保证数据私有
  • 2、一定要对数据初始化
  • 3、不要在类中使用过多的基本类型
  • 4、不是所有的域都需要独立的域访问器和域更改其
  • 5、将指责过多的类进行分解
  • 6、类名和方法名要能体现他们的职责
  • 7、优先使用不可变的类