Java面向对象
面向对象简称 OO(Object Oriented),20 世纪 80 年代以后,有了面向对象分析(OOA)、 面向对象设计(OOD)、面向对象程序设计(OOP)等新的系统开发方式模型的研究。
在 Java 语言中,一切皆是对象,Java把现实世界中的实体以对象的形式抽象地体现在编程世界中,一个对象代表了某个具体的实体,对象的属性代表了这个实体的特征,对象的方法代表了这个实体的能力。
面向对象的概念
Java 是面向对象的编程语言,对象就是面向对象程序设计的核心。所谓对象就是真实世界中的实体,对象与实体是一一对应的,也就是说现实世界中每一个实体都是一个对象,它是一种具体的概念。对象有以下特点:
- 对象都是某个类别的实例。
- 对象具有唯一性。
- 真实世界中的所有事物都可以视为对象。
- 对象具有变化的状态。
- 对象具有属性和行为。
面向对象与面向过程
- 面向过程代码松散,强调流程化解决问题。
- 面向对象代码强调高内聚、低耦合,先抽象模型定义共性行为,再解决实际问题。
面向对象的三大核心特性
面向对象开发模式更有利于人们开拓思维,在具体的开发过程中便于程序的划分,方便程序员分工合作,提高开发效率。面向对象程序设计有以下优点:
- 可重用性:代码重复使用,减少代码量,提高开发效率。
- 可扩展性:指新的功能可以很容易地加入到系统中来,便于软件的修改。
- 可管理性:能够将功能与数据结合,方便管理。
面向对象的设计思想之所以使程序设计更加完善和强大,主要是因为面向对象具有继承、封装和多态 3 个核心特性。
封装
封装是对象功能内聚的表现形式,在抽象基础上决定信息是否公开及公开等级,核心问题是以什么方式暴漏哪些信息。主要任务是对属性、数据、敏感行为实现隐藏,对属性的访问和修改必须通过公共接口实现。封装使对象关系变得简单,降低了代码耦合度,方便维护。
迪米特原则就是对封装的要求,即 A 模块使用 B 模块的某接口行为,对 B 模块中除此行为外的其他信息知道得应尽可能少。不直接对 public 属性进行读取和修改而使用 getter/setter 方法是因为假设想在修改属性时进行权限控制、日志记录等操作,在直接访问属性的情况下无法实现。
优点总结:
- 保护类中的信息,它可以阻止在外部定义的代码随意访问内部代码和数据。
- 隐藏方法实现的细节信息,只需要知道它是做什么的,不需要知道它具体是怎么实现的。
- 有助于建立各个系统之间的松耦合关系,提高系统的独立性。
- 提高软件的复用率,降低成本。
继承
继承用来扩展一个类,子类可继承父类的部分属性和行为使模块具有复用性,这是类之间的一种关系。Java 只支持单继承。。
继承是"is-a"关系,可使用里氏替换原则判断是否满足"is-a"关系,即任何父类出现的地方子类都可以出现。如果父类引用直接使用子类引用来代替且可以正确编译并执行,输出结果符合子类场景预期,那么说明两个类符合里氏替换原则。
多态
多态以封装和继承为基础,根据运行时对象实际类型使同一行为具有不同表现形式。多态指在编译层面无法确定最终调用的方法体,在运行期由 JVM 动态绑定,调用合适的重写方法。由于重载属于静态绑定,本质上重载结果是完全不同的方法,因此多态一般专指重写。
重载和重写
重载指方法名称相同,但参数类型个数不同,是行为水平方向不同实现。对编译器来说,方法名称和参数列表组成了一个唯一键,称为方法签名,JVM 通过方法签名决定调用哪种重载方法。不管继承关系如何复杂,重载在编译时可以根据规则知道调用哪种目标方法,因此属于静态绑定。
JVM 在重载方法中选择合适方法的顺序:
① 精确匹配。② 基本数据类型自动转换成更大表示范围。③自动拆箱与装箱。④ 子类向上转型。⑤ 可变参数。
重写指子类实现接口或继承父类时,保持方法签名完全相同,实现不同方法体,是行为垂直方向不同实现。
元空间有一个方法表保存方法信息,如果子类重写了父类的方法,则方法表中的方法引用会指向子类实现。父类引用执行子类方法时无法调用子类存在而父类不存在的方法。
重写方法访问权限不能变小,返回类型和抛出的异常类型不能变大,必须加 @Override 。
类之间的关系
类关系 | 描述 | 权力强侧 | 举例 |
继承 | 父子类之间的关系:is-a | 父类 | 小狗继承于动物 |
实现 | 接口和实现类之间的关系:cando | 接口 | 小狗实现了狗叫接口 |
组合 | 比聚合更强的关系:contains-a | 整体 | 头是身体的一部分 |
聚合 | 暂时组装的关系:has-a | 组装方 | 小狗和绳子是暂时的聚合关系 |
依赖 | 一个类用到另一个:depends-a | 被依赖方 | 人养小狗,人依赖于小狗 |
关联 | 平等的使用关系:links-a | 平等 | 人使用卡消费,卡可以提取人的信息 |