ADT+OOP

一、数据类型与类型检查

数据类型

基本数据类型:Primitives
对象数据类型:Object Reference Types
数据类型
对象类型形成层次结构(通过继承重写)。

类型检查

静态类型检查:在编译时进行类型检查。包括语法错误、函数名类名错误、参数数目类型错误、返回值类型错误。和类型有关。例如C语言中允许的int a然后if(a),但是java在静态类型检查就会对此报错。
动态类型检查:在运行时进行类型检查。包括非法参数值(如除零错误)、非法返回值、越界、空指针。和具体值有关。
注:有关返回值,需要在具体情境下分析具体是静态检查还是动态检查。

Mutable/Immutable

不变对象:一旦被创建,始终指向同一个值/引用。但是指向该对象的指针可以再指向另一个对象,故如下代码可以实现:

String s = "a";
s = s.concat("b"); // s = s + "b"

String s

可变对象:拥有方法可以修改自己的值/引用。例如:

StringBuilder sb = new StringBuilder("a");
sb.append("b");

StringBuilder
不变对象更为安全,但是对其多次拷贝产生大量临时拷贝,需要垃圾回收。
可变数据类型性能更好,而且可以在模块间传递,相当于全局变量。要想较为安全的使用,注意只有一个引用、局部变量。

值的改变、引用的改变、final

值的改变:内存的那个位置中存的值发生改变。
引用的改变:指针指向了另一个地址。
final修饰符:

  1. 用来修饰类则该类不能被继承。
  2. 用来修饰方法则该方法不能被重写。
  3. 用来修饰变量,若该变量为基本数据类型,则相当于定义了个常量;若该变量为对象数据类型,则对其的引用不能被改变,但是若是mutable则其值仍是也可能变化的。

防御式拷贝

使用目的:增强可变数据类型的安全性。
实现方法:给客户端传一个全新的对象,而不是在原对象的基础上修改。
弊端:频繁复制,不如一开始直接选择不可变数据类型了。

Snapshot diagram

  1. 基本类型的值:变量名–>变量值。
  2. 对象类型的值:变量名–>椭圆(可变用单线,不可变用双线),椭圆内顶上第一行写类型,下面写field等具体细节。
  3. 改变不可变对象:叉掉原来的箭头,画上新的。
  4. 改变可变对象:叉掉原来的值,添上新的。
  5. final修饰的不可变的引用:==>。
  6. 例子:
    Snapshot

二、设计规约

Specification、前置/后置条件

规约只需要讲清能做什么,不需要讲如何实现。
规约
方法前说明的规约包括前置条件后后置条件两部分:

  1. 前置条件:对客户端的约束,在使用方法时必须满足的条件。
  2. 后置条件:对开发者的约束,方法结束时必须满足的条件。
    契约:如果前置条件满足了,后置条件必须满足。
    事实上,静态类型声明也是一种规约,由编译器判断(即静态类型检查),方法前注释也是一种规约,人工判断。
    对于mutable对象,除非在后置条件里声明过,否则方法内部不应该改变输入参数。

行为等价性

即站在客户的角度,判断方法是否等价,判断标准即规约:均满足其规约,则等价。

规约的强度

前置条件更弱,后置条件更强,规约更强。把异常的作用归结到对后置条件的作用上,异常越多,后置条件越弱。
越强的规约在Diagramming specifications中越小(前提是二者有可比性),因为越强的规约,能满足他的方法越少,即圈中的点越少。

三、ADT

ADT操作的四种类型

  1. 构造器creator:由其他类型产生本类型。可以用构造函数实现,也可以由静态方法实现,后者实现方式称为工厂方法。
  2. 生产器producer:由本类型产生本类型,可以有其他类型的参与。
  3. 观察器observer:由本类型返回其他类型,可以有其他类型的参与。
  4. 变值器mutator:改变本类型对象属性。返回void一定是变值器。

表示独立性、表示泄露

表示独立性Representation Independence:客户对ADT的使用,不受ADT内部具体实现的改变而改变。
表示泄露:Client对成员变量的直接访问。如果改变成员变量的定义方式,显然会影响到Client的调用,显然违反表示独立性。也影响不变性。

不变量Invariants

恒为true的程序属性。如immutable。若用户可毁坏到不变量,则通过防御性拷贝可解决,而不要提供给客户对可变类型的直接引用。

表示空间R、抽象空间A、抽象函数AF、表示不变量RI

  1. 表示空间R:由实际的实施实体的值构成,是ADT开发者关注的。
  2. 抽象空间A:客户看到和使用的值。
  3. 抽象函数AF:R和A之间映射关系的函数,即如何去解释R中的每一个值为A中的每一个值。是满射(A中每个都要有至少一个在R中的表示),同时R中有不合法的值,在A中无映射值。
  4. 表示不变量RI:R中合法的表示值。

以注释的形式撰写AF、RI

在注释中,精确指明AF、RI,并在最后“自证清白”,给出rep exposure safety argument,证明代码内部无表示泄露,可包含如field均是private,大多是不可变类型,对可变类型返回时使用了防御性拷贝。

四、OOP

接口、抽象类、具体类

接口interface:作用是确定ADT规约。可以有多种实现类,一个类可以继承多个接口。变量定义时也习惯用接口来作引用类型。接口中每个方法都需要在具体类中实现,但是两者除外:default方法是可以在接口中就统一实现的功能,无需在类中再实现;static方法是可以用来构造工厂方法,使用户使用接口提供的工厂方法构造而不是ADT中的构造器,这样用户就不必知道具体实现方法,具体实现是开发者在static方法中选择。

抽象类abstract class:含有抽象方法,即只定义方法签名,还没有具体实现的方法。无法被实例化。全是抽象方法且没有字段field的抽象类即接口。

具体类class:用extends继承至多一个类,用implements完成任意个接口。类方法也叫实例方法。

多态

特设(Ad hoc)多态

方法重载overload:方法名相同但是参数不同,返回值可能相同可能不同。调用在编译时发生。

参数多态

泛型:在接口、实现类定义时使用。
注意,java实现泛型的原理是类型擦出(type erasure),在编译器中完成,因此实际运行时泛型都会消失,取而代之的是实际类型,因此有两个误区:
1.使用instanceof()检查泛型;
2.误认为List是List的子类。
对于第一个误区,尽量避免使用instanceof();对于第二个误区,java提供通配符(Wildcards)来满足需求,具体使用方法:

  1. <? extends xxx>是规定了上界为xxx,即允许传入xxx以及xxx的子类,不能对其执行“写”操作如add()因为不知道实例化的具体对象类型,只可以“读”如get()
  2. <? super xxx>是规定了下界为xxx,即允许传入xxx以及xxx的父类,不能对其执行“读”操作如get()因为不知道存放的对象类型,只可以“写”如add()。
  3. <?>可以传入一切类型,用object接收(因为相当于默认上界为object)。

子类型多态

通过继承重写override(方法签名和返回值均不能变),由LSP保证了不同类型的对象可以统一的处理而无需区分。调用在运行时发生,根据实际类型确定调用哪个方法。

五、ADT和OOP中的“等价性”

==和等价性equals()

前者为引用等价性,后者为对象等价性。即区分点在于是引用同一个对象还是被引用的对象的具体值相等。
但是Object中的equals其实也是在判断引用等价性,因此要在ADT中重写。

equals()的自反、传递、对称

重写时注意传进来的参数类型一定是Object,故先用instanceof()判断类型是否为想要的,不是则直接返回false,再取新变量由参数类型强转为需要的类型,根据该实际类型设计合适的自反、传递、对称的等价关系判断。

hashCode()

等价的对象的hashCode一定相等。
确保契约得到满足的一种简单而激进的方法是,hashCode总是返回一些常量值,因此每个对象的hash代码都是相同的。这满足了对象契约,但会对性能造成灾难性的影响,因为每个键都将存储在同一个插槽中,并且每个查找都将退化为沿长列。
标准是为用于确定相等性的对象的每个组件计算一个哈希代码(通常通过调用每个组件的hashCode方法),然后将它们结合起来,加入一些算术运算。表的线性搜索。

不可变对象的引用等价性、对象等价性

即==和equals()。

可变对象的观察等价性、行为等价性

观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致。
行为等价性:调用对象的任何方法都展示出一致的结果。
在JDK中,不同的mutable类使用不同的等价性标准:Date和List均是观察等价性,StringBuilder是行为等价性。
对于一般的mutable类型,就是行为等价性,即引用等价性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值