这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天
面向对象概述
面向过程或者说传统的程序设计通过设计一系列的算法来求解问题,“算法 + 数据结构 = 程序”。面向过程思想通过将问题分解为一个个的过程,然后每个过程去操作全局变量,最终达到问题的求解。
面向对象相对于面向过程思想更加抽象,面向对象的程序是由一个个对象组成的,一个对象包含用户公开的特定的功能方法和隐藏的功能实现,根本上说,只要对象能够完成特定的功能,就没必要关心它的具体实现。
举个例子,实现一个简单的浏览器。实现一个简单的浏览器,利用面向过程方法论需要2000+的过程和全局变量来实现;面向对象方法则需要100+类和每个类20个左右的方法实现。乍一看体量差不多,但是实际开发过程中,如果发生了错误,在2000+的过程中寻找错误位置和在一个类中寻找20多个方法的难度不是一个数量级的。
类和对象
类:构造对象的模板。对象:通过模板创建出来的实例。
public class 类名 {
成员变量/静态变量/静态初始化块
成员方法/静态方法 创建对象
构造器/初始化块 ----------> 类名 变量名 = new 类名();
内部类
}
上面的伪代码就可以说明类和变量的关系,类中包含了各种各样的模板,方法,变量,代码块和内部类。而对象创建出来以后就需要被调用或者说被使用。
使用对象,主要有两种类型:调用成员方法,使用成员变量。
Person p = new Person();
p.age = 12; // 使用成员变量,为成员变量赋值
p.sleep(); // 调用成员方法
对象三个重要的特性:行为(behavior)、状态(state)、标识(identifier)。行为 - 成员方法、状态 - 成员变量、标识 - 唯一ID。
对象的状态在实践中,通常只能通过类的成员方法来实现,否则会破坏一个对象的封装性。
注意事项:
- 类要使用大驼峰的命名规则来命名
- 一个 java 文件只有一个
public类,而且文件名和这个 public 类的名称保持一致- 成员变量的完整定义格式:
权限修饰符 数据类型 变量名称 = 初始化值;如果没有初始化值,那就是默认值。
类之间的关系
类之间的关系主要有:
- 依赖(uses-a)
- 聚合(has-a)
- 继承(is-a)
在实际时间过程中,对于类之间的关系如何命名,根据经验,可以通过当前对象和相关对象的生命周期来判断。
- 依赖:一个类的方法操作或者使用某个对象,那么这个类就依赖于另一个类。生命周期来看,这两个对象的生命周期之间没有关系,只存在比较弱的关系。
- 聚合:一个类的对象和另一个类的对象之间存在包含关系,这就是聚合。从生命周期来看,对象中包含的生命周期和这个对象没有强关系称之为聚合。这区别于组合,组合关系中对象和它包含的对象有一致的生命周期,是比聚合更加强的关系。
- 继承:一个类和它派生子类之间的关系,派生子类一般对父类进行了重写,或者对方法进行了扩展。生命周期来看,这个对象有多重身份也就是这条继承链上的所有身份。
封装性
封装,其实就是让一个类将其成员进行隐藏,对象代表什么,就封装相应的数据,并且提供数据相关的行为。
权限修饰符 private 就可以起到一定的封装效果。private 关键字可以修饰成员,被 private 修饰的成员只能在本类中使用,其他类包括派生类都不可以使用。
面向对象的封装性的关键在于:绝对不能让类中的方法直接访问其他类的实例字段。
遮蔽(shadow)
遮蔽(shadowing)就是局部变量和全局变量同名的时候,按照这个名称使用变量优先会使用局部变量。
public class Person {
private int age;
public void setAge(int age) {
System.out.println(age); // 方法参数
System.out.println(this.age); // 成员变量
}
}
为了避免这个问题,就需要 super 和 this 关键字来区别这个变量。
初始化块和静态初始化块
*初始化块(initialization block)*是 Java 中初始化对象的一种机制,Java 代码中可以有多个初始化块。
- 初始化块会按照类声明顺序执行代码块内容
- 初始化块中无法访问,定义在初始化块之前的字段
类似地,也会存在*静态初始化块(static initialization block)*用于初始化比较复杂的静态字段。
public class Block {
private long timestamp;
{
LocalDateTime date = LocalDateTime.now();
timestamp = date
.toInstant(ZoneOffset.of("+8"))
.toEpochMilli();
// 无法访问声明之后的字段
// year = date.getYear();
}
private int year;
{ year = LocalDateTime.now().getYear(); }
// 静态初始化块
private static int random;
static { random = new Random().nextInt(); }
}
对象的初始化
关于对象的初始化,在JVM中有详细解释,下面是一个非常简单的过程
- 类加载:加载类
- 内存中开辟空间
- 构造方法调用过程