面向对象的标准
基本概念:对象,类,属性,方法和接口
OOP的独特功能程序员
封装和信息隐藏 继承和重写 多态性,子类型和重载 静态与动态分派
Java中一些重要的Object方法
设计好的类
面向对象的历史
总结算法
面向对象的编程方法/语言应该具备类的概念做为中心概念。
语言应该可以为类和它的特征提供断言(即规范:前置条件,后置条件和不变量)和异常处理,依靠工具生成这些断言中的文档,而且可选地在运行时监视它们 时间。数据库
静态类型:一个定义良好的类型系统应该经过强制执行一些类型声明和兼容性规则来保证它接受的系统的运行时类型安全。编程
泛型(Genericity):用于“准备改变”和“为/重用设计”:应该能够编写具备表示任意类型的正式泛型参数的类。数组
继承(Inheritance):应该能够将一个类定义为从另外一个继承,以控制潜在的复杂性。安全
多态(Polymorphism):在基于继承的类型系统的控制下,应该能够将实体(表示运行时对象的软件文本中的名称)附加到各类可能类型的运行时对象。模块化
动态分派/绑定(Dynamic dispatch / binding):在一个实体上调用一个特性应该老是触发与所附加的运行时对象的类型相对应的特性,这在调用的不一样执行过程当中不必定是相同的。函数
对象工具
真实世界的物体有两个特征:它们都有状态和行为。
识别真实世界对象的状态和行为是从OOP角度开始思考的好方法。性能
对于你看到的每一个对象,问本身两个问题,这些现实世界的观察都转化为OOP的世界:
一个对象是一组状态和行为
状态 - 包含在对象中的数据。
行为 - 对象支持的操做
类
每一个对象都有一个类
类定义了类型和实现
松散地说,类的方法是它的应用程序编程接口(API)
静态与实例变量/类的方法
类成员变量:与类相关联的变量,而不是类的实例。 您还能够将方法与类关联 - 类方法。
不是类方法或类变量的方法和变量称为实例方法和实例成员变量。
总结:
静态方法不与任何特定的类实例关联,而实例方法(不带static关键字声明)必须在特定对象上调用。
Java的接口是一种用于设计和表达ADT的有用语言机制,其实现方式是实现该接口的类。
接口和实现
API的多个实现能够共存
在Java中,API由接口或类指定
一个接口能够有多种实现
Java接口和类
接口与类
类确实定义了类型
但更喜欢使用接口
问题:打破抽象边界
接口的优势
接口指定了客户端的契约,仅此而已。
为何有多个实现
不一样的表现
不一样的行为
性能和行为每每不尽相同
接口总结
减小错误保证安全
容易明白
准备好改变
信息隐藏
将精心设计的模块与很差的模块区分开来的惟一最重要的因素是其隐藏内部数据和其余模块的其余实施细节的程度。
设计良好的代码隐藏了全部的实现细节
被称为信息隐藏或封装,是软件设计的基本原则。
信息隐藏的好处
将构成系统的类分开
加速系统开发
减轻了维护的负担
启用有效的性能调整
增长软件重用
经过接口隐藏信息
使用接口类型声明变量
客户端只能使用接口方法
客户端代码没法访问的字段
但咱们到目前为止
成员的可见性修饰符
private - 只能从声明类访问
protected - 能够从声明类的子类(以及包内)
public - 从任何地方访问
信息隐藏的最佳实践
仔细设计你的API
只提供客户须要的功能,其余全部成员应该是私人的
您能够随时在不破坏客户的状况下让私人成员公开
(1)重写
可重写的方法和严格的继承
可重写方法:容许从新实现的方法。
严格的继承
final
final字段:防止初始化后从新分配给字段
final方法:防止重写该方法
final类:阻止继承类
重写
方法重写是一种语言功能,它容许子类或子类提供已由其超类或父类之一提供的方法的特定实现。
当子类包含一个覆盖超类方法的方法时,它也可使用关键字super调用超类方法。
重写的时候,不要改变原方法的本意
(2)抽象类
抽象方法和抽象类
抽象方法:
抽象类:
接口:只有抽象方法的抽象类
具体类⇒抽象类⇒接口
(1)三种多态性
特殊多态(Ad hoc polymorphism):当一个函数表示不一样且可能不一样种类的实现时,取决于单独指定类型和组合的有限范围。 使用函数重载(function overloading)在许多语言中支持特设多态。
参数化多态(parametric polymorphism):当代码被写入时没有说起任何特定类型,所以能够透明地使用任何数量的新类型。 在面向对象的编程社区中,这一般被称为泛型或泛型编程。
子类型多态(也称为子类型多态或包含多态):当名称表示由一些公共超类相关的许多不一样类的实例。
(2)特殊多态和重载
当函数适用于几种不一样的类型(可能不会显示公共结构)而且可能以不相关的方式表现每种类型时,能够得到特殊多态。
(3)重载
重载的方法容许您在类中重复使用相同的方法名称,但使用不一样的参数(以及可选的不一样的返回类型)。
重载方法一般意味着对于那些调用方法的人来讲会更好一些,由于代码承担了应对不一样参数类型的负担,而不是在调用方法以前强制调用方执行转换。
函数重载能够在不一样的实现中建立同名的多个方法。
重载是一种静态多态
重载规则
函数重载中的规则:重载函数必须因参数或数据类型而有所不一样
重写与重载
不要混淆覆盖派生类中的方法和重载方法名称
(3)参数多态性和泛型编程
当一个函数在一系列类型上统一工做时得到参数多态性; 这些类型一般具备一些共同的结构。
泛型编程是一种编程风格,其中数据类型和函数是根据待指定的类型编写的,随后在须要时做为参数提供的特定类型实例化。
泛型编程围绕从具体,高效的算法中抽象出来以得到可与不一样数据表示形式结合的泛型算法来生成各类各样有用软件的想法相关。
Java中的泛型
类型变量是一个不合格的标识符。
若是一个类声明一个或多个类型变量,则该类是通用的。
泛型类:其定义中包含了类型变量
若是声明了类型变量,则interface是通用的。
若是声明类型变量,则方法是通用的。
类型变量
使用菱形运算符<>来帮助声明类型变量。
一些Java泛型细节
能够有多个类型参数
Wildcards通配符,只在使用泛型的时候出现,不能在定义中出现
通用类型信息被擦除(即仅编译时)
没法建立通用数组
(4)子类多态性
子类
一个类型是一组值。
相反,这些值都是ArrayList对象或LinkedList对象,或者是实现List的另外一个类的对象。
子类型只是超类型的一个子集
继承/子类型的好处:重用代码,建模灵活性
在Java中:每一个类只能直接继承一个父类; 一个类能够实现多个接口。
“B是A的子类型”意思是“每一个B都是A.”
在规格方面:“每一个B都符合A的规格”。
静态检查子类型
但编译器没法检查咱们是否以其余方式削弱了规范:
若是你在Java中声明了一个子类型(例如,实现一个接口),那么你必须确保子类型的规范至少和超类型同样强。
子类型的规约不能弱化超类型的规约。
子类型多态
子类型多态:不一样类型的对象能够被客户代码统一处理子类型多态:不一样类型的对象能够统一的处理而无需区分
每一个对象根据其类型行为(例如,若是添加新类型的账户,客户端代码不会更改)从而隔离了“变化”
Liskov替换原则(LSP):
instanceof
测试某个对象是否为给定类的运算符
建议:若是可能,避免使用instanceof(),而且从不在超类中使用instanceof()来检查针对子类的类型。
类型转换
有时你想要一种不一样于你已有的类型
若是你知道你有一个更具体的子类型,颇有用
可是若是类型不兼容,它会获得一个ClassCastException
建议:
动态分派是选择在运行时调用多态操做的哪一个实现的过程。
肯定在运行时要调用哪一种方法,即对重写或多态方法的调用可在运行时解决
做为示例,File对象和Database对象都有一个StoreRecord方法,可用于将人员记录写入存储。 他们的实现不一样。
一个程序持有一个对象的引用,该对象多是一个File对象或一个数据库对象。 它多是由运行时间设置决定的,在这个阶段,程序可能不知道或关心哪个。
当程序在对象上调用StoreRecord时,须要肯定哪些行为被执行。
该程序将StoreRecord消息发送给未知类型的对象,并将其留给运行时支持系统以将消息分派给正确的对象。 该对象实现它实现的任何行为。
动态分派与静态分派造成对比,其中在编译时选择多态操做的实现。
动态分派的目的是为了支持在编译时没法肯定多态操做的适当实现的状况,由于它依赖于操做的一个或多个实际参数的运行时类型。
静态分派:编译阶段便可肯定要执行哪一个具体操做。
重载的方法使用静态分派,而重写的方法在运行时使用动态分派。
动态分派不一样于动态绑定(也称为动态绑定)。
提早/静态绑定
每当发生静态,私有和最终方法的绑定时,类的类型由编译器在编译时肯定,而且绑定在那里和那里发生。
推迟/动态绑定
重写父类和子类都有相同的方法,在这种状况下,对象的类型决定了要执行哪一种方法。 对象的类型在运行时肯定。
动态方法分派
1.(编译时)肯定要查找哪一个类
2.(编译时)肯定要执行的方法签名
3.(运行时)肯定接收器的动态类别
4.(运行时)从动态类中,找到要调用的方法
10 Java中的一些重要的Object方法
equals() - 若是两个对象“相等”,则为true
hashCode() - 用于哈希映射的哈希代码
toString() - 可打印的字符串表示形式
toString() - 丑陋而无信息
equals&hashCode - 身份语义
不可变类的优势
简单
本质上是线程安全的
能够自由分享
不须要防护式拷贝
优秀的积木
如何编写一个不可变的类
不要提供任何变值器
确保没有方法可能被覆盖
使全部的领域最终
使全部字段保密
确保任何可变组件的安全性(避免重复曝光)
实现toString(),hashCode(),clone(),equals()等。
什么时候让类不可变
老是,除非有充分的理由不这样作
老是让小型“价值类”永恒不变!
什么时候让类可变
类表示状态改变的实体
若是类必须是可变的,则最小化可变性
仿真和面向对象编程的起源
20世纪60年代:Simula 67是第一个由Kristin Nygaardand Ole-Johan Dahl在挪威计算中心开发的面向对象语言,用于支持离散事件模拟。 (类,对象,继承等)
“面向对象编程(OOP)”这个术语最先是由施乐PARC在他们的Smalltalk语言中使用的。
20世纪80年代:面向对象已经变得很是突出,而其中的主要因素是C ++。
NiklausWirth用于Oberon和Modula-2的模块化编程和数据抽象;
埃菲尔和Java
面向对象的标准
基本概念:对象,类,属性,方法和接口
OOP的独特功能
封装和信息隐藏 继承和重写 多态性,子类型和重载 静态和动态调度
Java中一些重要的Object方法编写一个不可变的类OOP的历史