软件构造第三章复习总结

Abstract Data Type (ADT) and Object-Oriented Programming (OOP)抽象数据类型和面向对象编程,本章知识点比较多,包括如下:
基本数据类型、
对象数据类型
静态类型检查、
动态类型检查
Mutable/Immutable
▪ 值的改变、引用的改变
▪ 防御式拷贝
▪ Snapshot diagram
▪ Specification、前置/后置条件
▪ 行为等价性
▪ 规约的强度
▪ ADT操作的四种类型
▪ 表示独立性
▪ 表示泄露
▪ 不变量、表示不变量RI
▪ 表示空间、抽象空间、AF
▪ 以注释的形式撰写AF、RI
▪ 接口、抽象类、具体类
▪ 继承、override
▪ 多态、overload
▪ 泛型 ▪ 等价性equals()和==
▪ equals()的自反、传递、对称性
▪ hashCode()
▪ 可变对象的观察等价性、行为等价性

我们首先来看 Data type in programming languages,编程语言中的数据类型
boolean: Truth value (true or false).
– int: Integer (0, 1, -47).
– double: Real number (3.14, 1.0, -2.1).
– String: Text (“hello”, “example”).
primitive types(基本数据类型)
– int (for integers like 5 and -200, but limited to the range ± 2^31, or roughly ± 2 billion)
– long (for larger integers up to ± 2^63)
– boolean (for true or false)
– double (for floating-point numbers, which represent a subset of the real numbers)
– char (for single characters like ‘A’ and ‘$’ )

object types(对象数据类型)
– String represents a sequence of characters.
– BigInteger represents an integer of arbitrary size

基本数据类型小写开始,对象数据类型大写开始
Primitives基本数据类型
int, long, byte, short, char, float, double, boolean
Immutable On stack, exist only when in use 在栈上,只有使用的时候才存在

Object Reference Types 对象数据类型
Some mutable, some not
On heap, garbage collected 在堆里,进行垃圾回收
使用成本高

Object类是所有类 的基类
所有类默认都继承了 Object类
子类是父类的一个实例, 如 Student 和 Teacher 都可以设计为Person的子类
从它的父类中继承可见域和方法。
可以重写方法改变它的行为。

基本数据类型的包装类
将基本数据类型封装为对象 Boolean, Integer, Short, Long, Character, Float, Double
尽可能少用 语言会自动进行转换
例子:
List list = new ArrayList(); list.add(1); list.add(50); 1和50不是对象类型,但编译能够通过,自动完成转换。但会降低效率
list.add(Integer.valueOf(1)); //自动完成的操作 list.add(Integer.valueOf(50));

Java is a statically-typed language java是一个静态类型语言
在编译时需要知道所有变量的类型,编译器可以推断所有表达式的 类型

Static checking: the bug is found automatically before the program even runs.
bug在程序运行前自动发现

Dynamic checking: the bug is found automatically when the code is executed.
bug在程序运行时发现错误

No checking: the language doesn’t help you find the error at all. You have to watch for it yourself, or end up with wrong answers
不帮助你找到错误,你需要自己检查。

静态检查针对类型,与变量 特定值无关的错误
动态检查针对由特定值引起的错误
改变变量和改变值的区别
对变量赋值是在改变变 量的指向,指向不同的值
改变可变变量的内容时 ,是在改变变量内部内容的引用

不变性是一种主要的设计原则 不变数据类型创建完后,值不可修改
不变引用,一旦指定引用位置,不可再次指定
To make a reference immutable, declare it with the keyword final:
final int n = 5;
为了使变量不可变,用final定义它。

Final关键 字对不可变引用提供了静态检查的支持。
利用final来声明方 法的参数和局部变量。

有利于代码理解和编译器的静态检查

A final class declaration means it cannot be inherited
不能被继承
A final variable means it always contains the same value/reference but cannot be changed
值不变不可改变
A final method means it cannot be overridden by subclasses
不能被子类重载

String as an immutable type
A String object always represents the same string.
他总是表示同一字符串

To add something to the end of a String, you have to create a new String object:
想在string末尾添加东西,你必须创建一个新的string对象

可以用concat方法进行连接,变成一个新的对象

StringBuilder as a mutable type
This class has methods that change the value of the object, rather than just returning new values:这个类的append方法可以改变对象的值,而不是只返回新的值。
当仅有一个引用时,二者 的使用区别不大 当有多个引用时,二者的区别很大

Using immutable strings, this makes a lot of temporary copies
用不可变类型会制造许多临时的副本。
immutable types are safer from bugs, easier to understand, and more ready for change.
不可变类型更安全易于理解。

传递可变对象容易产生潜在错误,且难以跟踪
采用不可变类型,可通 过内存共享相同的值,降低复制带来的内存空间占用
只 在局部使用或者只有一个引用时,可变类型的使用是安全的
对可变类型的多个引用(别名)是带来风险的原因

Snapshot diagram

接下来我们再次了解快照表
Snapshot diagrams represent the internal state of a program at runtime – its stack (methods in progress and their local variables) and its heap (objects that currently exist).
快照表代表了运行时程序的内部状态,他的栈( 进程中的方法和他们的本地变量),它的堆(现存的对象).

Snapshot diagrams give us a way to visualize the distinction between changing a variable and changing a value快照表给我们一个方法去显现这个差异在改变一个变量和一个值之间的。

Primitive values are represented by bare constants.
基本数据类型的值被空箭头和常量代表。

An object value is a circle labeled by its type
一个对象的值是一个圈被他的类型标记。

Immutable objects (intended by their designer to always represent the same value) are denoted in a snapshot diagram by a double border, like the String objects in our diagram
不可变对象被表示成一个双边界

an immutable reference (final) is denoted by a double arrow. 不可变参数也被双边界表示。

The int[] array type includes all possible array values, but a particular array value, once created, can never change its length.
数组类型包括所有可能的数组值,但一旦被创建,就不能改变长度。

迭代一个数组
Iterating an array
int max = 0; for (int i=0; i<array.length; i++) { max = Math.max(array[i], max); }
迭代一个列表
Iterating a List int max = 0; for (int x : list) { max = Math.max(x, max); }
We cannot create a collection of primitive types.
我们不能创建一个基本类型集合

Iterator的快照表
在这里插入图片描述

Primitives cannot be null and the compiler will reject such attempts with static errors基本数据类型是非空的,并且编译器将会拒绝错误的静态尝试。
对两部分代码接口处行为的错误理解

规格说明给了实现者实现的自由,在保证约定 下,可以自由修改实现
通过在说明中增加对输入的限 定,省略掉耗时的正确性检查工作,提升效率。(保证输入正确性 的责任由调用者承担)

Designing Specification
设计规格
final is also a form of documentation, a claim that the variable will never change after its initial assignment.
声 明变量是final类型的也是一种文档约定 ,并且它声明之后不会再进行改变。

规格说明是团队开发的关键,是分配责任的基础 ,规格说明是实现者和使用者之间的一种契约,实现者有责 任满足契约,使用者可以信赖契约 。 对双方都有约束

确定行为的等价, 关键是一个规格说明实现是否可以替换另一个
A specification of a method consists of several clauses:一个规格说明包括几条
– Precondition , indicated by the keyword requires
前置条件,由关键需求指明

– Postcondition , indicated by the keyword effects
后置条件,由关键效果指明

– Exceptional behavior: what it does if precondition violated
额外行为,如果前置条件违反,会发生什么

The precondition is an obligation(义务) on the client
前置条件是顾客的义务

The postcondition is an obligation on the implementer of the method. 
后置条件是方法实施者的义务

规格说明蕴含了以下逻辑:如果 前置条件满足了,则后置条件必须满足

反之,如果前置条件不满足,后置条件 则无需满足

前置和后置条件中对类型的声明,将 由编译器进行检查,确保正确性
其余部分通过注释的形式进行描述,由人来保证正确性
Parameters are described by @param clauses and results are described by @return and @throws clauses.参数为param部分,结果为return或throw部分

前置条件放进param,后置条件放进return或throw
在这里插入图片描述

以上为规格说明的例子。
对于可变化的方法(如果没有 明确说明,则默认输入值是不可变的)
除非另有说明,保持不可变 ,不对输入进行修改
A specification S2 is stronger than or equal to a specification S1 if – S2’s precondition is weaker than or equal to S1’s – S2’s postcondition is stronger than or equal to S1’s, for the states that satisfy S1’s precondition
规格说明s2强于s1的条件是前提条件弱或等于s1,s2的后置条件强于或等于s1

要求的更少 承诺 的更多则规格说明更强

一个规格说明定义了一个区域,其中包含的点为其 实现

一个实现或者满 足规格说明(区域内),或者不满足(区域外)
规格说明图表如下
在这里插入图片描述
故规格说明越强,区域越小
设计一个方法的首要任务是编写规格说明
如 仅在类的内部调用,则可以通过仔细检查调用该方法的所有位置来确 保前提条件的满足
如果是public的方法,则适宜采用后置条 件(抛出异常)

接下来我们看一下抽象数据类型
可变类型的对象可以被修改,是因 为提供了可修改其状态的操作。
Classifying the operations of an abstract type

给抽象数据类型分类:
Creatorscreate new objects of the type. 产生类型的新对象 – A creator may take an object as an argument, but not an object of the type being constructed.
一个creator可能把一个对象作为一个论证,而不是一个正在被构造的对象类型。
比如Arrays.asList().方法 String.valueOf() (返回参数的字符串形式)

Producers create new objects from old objects of the type. 在已有对象 基础上产生新的对象 比如concat()方法

Observerstake objects of the abstract type and return objects of a different type. 输入抽象类型的对象,返回其他类型的对象 比如size()方法

Mutatorschange objects. 改变对象 比如add方法。
类型是由其操作集以及 规格说明所表征的。

Representation Independence
好的ADT应该是表示独立的 只有当我们通过前置条件和后置条 件充分明确了ADT的操作,使调用者知道可以依赖哪些内容,实现者 知道可以安全更改哪些内容,此时才可以修改内部表示

这意味着抽象类型的使用与其表示(用于实现它的实际数据结构或数据字段)无关,因此表示中的更改对抽象类型本身之外的代码没有影响

例如,List提供的操作与list是表示为链表还是数组无关。

Rep Invariant and Abstraction Function
表示不变量和抽象函数

R: the space of representation values (rep values) consists of the values of the actual implementation entities. 实现时用到 的值空间

A: the space of abstract values consists of the values that the type is designed to support. 需要支持的值空间

Then the rep space R contains Strings, and the abstract space A is mathematical sets of characters.如图然后,rep空间R包含字符串,抽象空间A是数学字符集
在这里插入图片描述

AF : R → A
The arcs in the diagram show the abstraction function
表中的弧线展示的是抽象抽象函数

A rep invariant that maps rep values to booleans:
RI : R → boolean
® is true if and only if r is mapped by AF
如果被抽象函数匹配成功则是true,否则false

RI告诉我们空间R中的r是否被AF映射到了空间A中的某个值

RI形成了空间R的一个子集(子集中的 所有元素均被AF映射到了空间A中)
在这里插入图片描述
ri和af的例子
即使相同的表示值空间和相同的 表示不变性RI,我们仍然可以用不同的抽象函数AF来映射。

Beneficent mutation
有益的改变
抽象值永远不可改变
确保其映射的抽象值不变前提下,表示值可 以变化

AF是多对一的映射,rep value改变为了“多”中的另外一个。

在类中说明AF、RI、不变性,在定义Rep的 位置
RI AF和防止表示泄露
在这里插入图片描述
良好设计的ADT,可以替代spec 中的部分preconditions
静态方法无法调用非静态成员(方法和变量)

一个接口可以扩展其他接口

一个类可以实现多个接口

接口不能有构造方法,所以创 建对象时需要调用某个具体实现的构造方法

. 调用者理解ADT时只需要理解接口即可

调用者不能在 ADT的表示上创建无意的依赖

抽象数据类型的多个不同表示可以共存于同一个程序中, 作为实现接口的不同类

ADT的规格说明中,对方法的实现未明 确指定,为实现提供了自由,可以有多种方式实现
一个类可以 实现多个接口,展现多个视图,是对Java不支持多继承的一种补偿
通过对多个实现在性能和bug free方面的比较,进行实现的选择
内部数据和 实现细节的隐藏程度是模块化设计质量评价的最重要标准
API同实现分离
模块间只通过API通讯
private – Accessible only from declaring class
protected – Accessible from subclasses of declaring class (and within package)
public – Accessible from anywhere
在这里插入图片描述
可以在不妨碍调用者的情况下,在后期将私有变为 公有

不能进行相反操作,会破坏调用者的使用

子类 可以重新实现父类中的方法
默认父类中的方法均是可被重写的
final只能继承,不能重写
子类中可以通过super关键字调用父类中被重写的方法

Abstract method: 只有定义没有实现

Abstract class:抽象类不能实例化 继承某个抽象类的子类在实例化时,所有父类中的 抽象方法必须已经实现
An abstract class which has only abstract methods
多态性是指为不同类型的实体提供一个接口,或者使 用一个符号来表示多个不同的类型。

一个函数可以 有多个同名的实现(方法重载)

一个类型名字可 以代表多个类型(泛型编程)

一个变量名字可以代表多个类的实例( 子类型)

重载是指在一个类中存在多个同名函数,必须具有不同的参数 列表,返回值类型可同可不同

重载为调用者带来了方便(便于记忆同类方 法的名字)
可以根据需要选择方法的 实现

静态的多态,通过 参数列表决定依赖哪个实现
在编译时决定调用哪个方法

对某个方法 的重载可以在一个类中进行,也可以在子类中进行。此时需要注意同重写 的区别:如果父类和子类中两个方法的签名相同,则为重写;名称一样, 参数列表不一样时,则为重载

重写时父类和子类中的方法具有相同的签名
签名不同时则为重载
子类重载了父类的 方法后,子类仍然继承了被重载的方法

参数多态性是指方法针对多种类型时具有同样的行为 (这里的多种类型具有通用的结构),此时可使用统一的类型表达多种类型

在运行时根据具体指定类型确定(编 译成class文件时,会用指定类型替换类型变量)

泛型编程是一种编程风格,其中数据类型和函数是根据待 指定的类型编写的,随后在需要时根据参数提供的特定类型进行实例 化。

泛型编程围绕“从具体进行抽象”的思想,将采用不同数据表示的 算法进行抽象,得到泛型化的算法,可以得到复用性、通用性更强 的软件。

类中如果 声明了一个或多个泛型变量,则为泛型类

Set是泛型类型的一个示例:一种类型,其规范是根据稍后要填充的占位符类型

泛型类/接口,是在实例化类的时候指明泛型的具体类型(类型擦除); 泛型方法,是在调用方法的时候指明泛型的具体类型。
静态方法 不能使用所在泛型类定义的泛型变量
如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方 法 。
采用同样的 方式访问对象,会得到不同的行为
抽象类是一种方便的混合(介于接 口和具体实现类之间 )
B是A的子类型,当且仅当B的规格说明至少同A的一样强
避免向下类型转换
尽可能避免用 instanceof,特别是在超类中检查某个对象是否是其子类的对象
除了在equals()方法中,不要使用instanceof,会带来类型不安全
决定在运行时一个具有多态的操作,哪个具体实 现被选择执行
当需要通过value相关信息 判定相等时,需要重写
equals & hashCode
toString() - 丑陋且没有信息 - 你知道你的对象是什么让你可以做得更好 - 除非你知道它不会被调用,否则总是重写
可变类型通常存在一个具备复制功能的构造方法
防御式拷贝的方法
在这里插入图片描述
同样是防御式拷贝在这里插入图片描述
用抽象函数或者是关系来表示相等
在这里插入图片描述

The instanceof operator tests whether an object is an instance of a particular type.
instanceof操作方法检测一个对象是否是一个特定类的实例
使用equals方法判定相等的两个对象,其 hashCode必须产生相同的结果
首先利用hashCode()产生的hashcode确定slot(index)
再用 equals()方法在bucket中找到匹配的key
两个对象equals操作相等,则hashcode必须相等。因此,重写equals时,必 须重写hashCode。
最简单方法:让所有对象的hashCode为同一 常量,符合contract,但降低了hashTable效率
. 通过 equals计算中用到的所有字段的hashCode组合出新的hashCode
大部分语言中都是采用对象的内存地址作为默认hashcode
mutations affect the result of equals() and hashCode变化影响了equal和hashset的结果
不可 变类型应该重写equals()和hashCode()
可变类型不应该重写equals()和hashCode() ,采用Object默认实现的即可。. 客户端如果需要判断两个 对象的观察等价性,可以重新定义一个方法
想要直接相等,必须在±127之内,否则不可,但是equals方法一直相等。
在这里插入图片描述
在这里插入图片描述
The abstraction function is the basis for equality in immutable data types.
不可变数据类型中,抽象函数是等价性基础。
Reference equality is the basis for equality in mutable data types
参数等价性是可变类型相等的基础
Reflexive自反的: E(t,t) ∀t∈T – symmetric对称的: E(t,u) ⇒ E(u,t) – transitive传递的: E(t,u) ∧ E(u,v) ⇒ E(t,v)
以上就是第三章的内容,内容比较多,大概学习了一下内容: 基本数据类型、对象数据类型 ▪ 静态类型检查、动态类型检查 ▪ Mutable/Immutable ▪ 值的改变、引用的改变 ▪ 防御式拷贝 ▪ Snapshot diagram ▪ Specification、前置/后置条件 ▪ 行为等价性 ▪ 规约的强度 ▪ ADT操作的四种类型 ▪ 表示独立性 ▪ 表示泄露
▪ 不变量、表示不变量RI ▪ 表示空间、抽象空间、AF ▪ 以注释的形式撰写AF、RI ▪ 接口、抽象类、具体类 ▪ 继承、override ▪ 多态、overload ▪ 泛型 ▪ 等价性equals()和== ▪ equals()的自反、传递、对称性 ▪ hashCode() ▪ 可变对象的观察等价性、行为等 价性

.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值