软构总复习5
本来以为复习前能把我C++多态的文章发出来,看来是泡汤了。。。
其实上午我已经考完了嘿嘿,对于试题我闭口不谈了,感谢张佬、颜神和冯佬的讲座!!!
等着把lab3写了就可以搞事情了,我可有太多想干的事儿了!!但是博客还是要写的。我这一看“软件构造”的博客全是我同学,顺着我同学找下去还是我同学。。
- 理解方法规约及其条件的含义,会为方法设计规约(必考)
- 理解ADT的含义及表示独立性,能够分析AF/RI/rep(必考)
- 理解Java中类、接口、继承、重写、重载、泛型的语言层面上的机制,能够起码看懂其代码,能够分析它们(选择题必考)
- 能够分析并解决类设计中潜在的表示泄露的风险(大题必考)
- 理解ADT对象的等价性,能够分析equals和hashCode的作用或行为(选择题必考)
所谓ADT-抽象数据类型,强调作用于数据之上的操作,并不关心数据具体是怎么存储的。例如
我们的字母集合,只对它定义了操作,它的元素到底是怎么存的?用户不需要知道。可以是字
符串,可以是字符数组,可以是哈希表,可以是红黑树……
? ADT可以有4种操作:
? ①构造器creator,输入一些其它类型的对象,创建一个该ADT对象。例如创建一个新集合new()
或者现实中的构造函数。
? ②生产器producer,通过该ADT的旧对象,创建一个该ADT的新对象,例如计算当前集合与S的
交集的方法ins(S)。
? ③观察器observer,通过该ADT本身的数据以及传入参数,计算得到其它类型的值。例如检查
集合里是否有x的方法find(x)。
? ④变值器mutator,作出“修改ADT内部数据”的行为,是可变对象与不可变对象的本质区别!例
如将x加入集合并返回加入x后的集合大小的方法add(x)
? 接口相当于规定了ADT所需的未实现的操作(方法),这是用户所关注的。
? 类真正地在代码层面实现了接口规定的ADT操作,并且实现了ADT内部的数据存储
接口实际上可以通过default或者static直接编写方法实现。
? 例**1.**我不希望客户端得知具体类名,但客户端需要创建实例对象。基于static的工厂方法
? 例**2.**我突然想为字母集合ADT增加一个获取集合大小的方法size(),但又不希望修改已经实
现的具体类。在接口中就已实现默认操作的default方法
方法规约(spec)
更强的规约:前置条件更弱,后置条件更强,满足更强规约的方法一定能替代满足更弱规约的功能,客户端肯定更喜欢强规约方法(有更
大的自由度),但这增加了实现者的压力……(例:右边的add的规约强于左边的)
AF/RI/rep
? 对于ADT,客户端是无法看到其内部表示属性(rep)的,客户端只会看到ADT在表面上展现出来
的东西,即,ADT做了一个由表示空间?到抽象空间(A)的映射AF。
? 不是所有表示属性rep都能映射到相应的抽象值的(即有一些rep是非法的),那么任何时刻
ADT的rep都必须满足一定规则(合法),即表示不变量RI。
? 有时应该引入一个方法checkRep检查rep是否满足RI
表示独立性与表示泄露
? 表示独立性是指,客户端使用ADT时无需考虑(也不应该知道,更不应该直接访问
到)其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端。
? 如果ADT不幸地让客户端得到了自己内部表示(可变对象)的引用,那么客户端就可
以不通过ADT的操作,而可以通过非法后门修改ADT的内部表示,产生表示泄露。
继承与重写
? 一个类child可以继承另一个类father的全部方法与属性,在运行时存在继承关系的类型对象可
以互相转换。子类型也可以重写(override)父类的方法,替换为自己的实现代码。
? 例:我希望对类StringSet进行扩展,创建一个可记录操作日志的类StringLogSet
Java中常用类的接口实现与继承
? 容器类可以有不同的底层实现,但它们的操作都较为统一,表示为接口实现的形式。例如,
ArrayList和LinkedList都实现了接口List,都能实现列表的统一操作,但分别基于数组
和链表实现。HashMap<K,V>和TreeMap<K,V>都实现了接口Map<K,V>,都能实现映射的统一操作,但
分别基于哈希表和红黑树实现。HashSet和TreeSet都实现了接口Set,都能实现集合的统
一操作,但分别基于哈希表和红黑树实现。
? 所有引用类型的最终祖先类都是Object,都具有等价性判断equals()、哈希函数hashCode()和字符
串转换toString()方法,可以重写它们。
? Integer、Double等表示数值的引用类型(跟int、double这些非引用的内置类型并非一回事!)都继
承自Number类,都具有转换为其它数值类型的方法(例如intValue())。
? 所有异常类都继承自Exception,对于父异常的catch能够捕获子异常
ADT的等价性与equals()
? ADT的等价性是对于客户端角度而言的,要么,两个对象通过AF映射到相同的抽象值,要么,两个
对象能做出效果相同的行为。不一定非得让rep完全一致。
? 所有对象都继承了Object.equals(),我们可以在类中重写它,从而定义自己的等价规则。注意
equals()与==不是一回事,后者仅仅判断两个引用是否指向同一对象。如果不重写
Object.equals(),那么默认效果和==是一样的。
? 对于可变对象,除了上述的“观察等价性”,还会有一种“行为等价性”,如果两个对象这个时刻等价,
那么不管之后干了什么,这两个可变对象仍然是等价的。(一般和==一样,当且仅当是同一对象,
例如**StringBuilder,**我们常用的除它之外的类一般都是观察等价性,如String、List)
== 判引用相等;equals需要重写,否则默认和 == 作用相同
string和list的equals都进行了重写,是判断内容相等;而stringBuilder的equals是判断引用相等
由于equals的参数必须是Object,所以需要先检查类型是否匹配
hashCode
? Object.hashCode()计算对象的哈希值,将对象映射为一个整数,使得等价的对象具有
相同的哈希值。好的哈希算法应当使得不等价对象的哈希值尽量不同。
? hashCode()一般用在基于哈希表的集合类中(HashMap、HashSet)。查找一个对象时,
先通过hashCode直接找到对象对应的桶,再在桶里一个个用equals比较。
? Object.hashCode()默认直接返回对象的地址,即对象哈希值相同当且仅当为同一个对
象(引用一样),当使用了自定义的等价规则时,需要重写hashCode。
.重载
? 重载(overload)机制使得同一个类中的多个方法可以有相同的名字,前提是它们
有长度不同的参数列表,或者对应不同的参数类型,起码,得让编译器在进行静态
检查的时候通过你调用时传入的参数判断实际上应该选择哪个方法。重载也可以发
生在父类与子类之间(子类重载父类的方法)
我们小学期见吧~ 嘘,希望假期能把C++和Linux系统编程更完,应该没人看到这儿,嘘~
|