1,2,3章
- Five key quality objectives of software construction
- How OOP improves quality
- Static Typing vs. Dynamic Typing
- Static Checking and Dynamic Checking
- Immutable Wrappers
- ADT
Five key quality objectives of software construction
– Easy to understand: elegant and beautiful code / understandability
– Ready for change: maintainability and adaptability
– Cheap for develop: design for/with reuse: reusability
– Safe from bugs: robustness
– Efficient to run: performance
How OOP improves quality
Correctness: encapsulation, decentralization
Robustness: encapsulation, error handling
Extendibility: encapsulation, information hiding
Reusability: modularity, component, models, patterns
Compatibility: standardized module and interface
Portability: information hiding, abstraction
Ease of use: GUI components, framework
Efficiency: reusable components
Timeliness: modeling, reuse
Economy: reuse
Functionality: extendibility
Static Typing vs. Dynamic Typing
静态类型语言 – 在编译阶段进行类型检查
动态类型语言 – 在运行阶段进行类型检查
Static Checking and Dynamic Checking
静态检查:关于“类型”的检查,不考虑值
动态检查:关于“值”的检查
静态类型检查 >> 动态 >> 无检查
静态类型检查:可在编译阶段发现错误,避 免了将错误带入到运行阶段,可提高程序正 确性/健壮性
Static checking
Syntax errors 语法错误
Wrong names 类名/函数名错误
Wrong number of arguments 参数数目错误
Wrong argument types 参数类型错误
Wrong return types 返回值类型错误
补充:如果编译器无法确定final变量不会改变,就提示错误,这也是静态类型检查的一部分
Dynamic checking
Illegal argument values 非法的参数值. 例如:除0
Unpresentable return values 非法的返回值
Out-of-range indexes 越界
Calling a method on a null object reference. 空指针
Immutable Wrappers
– Collections.unmodifiableList
– Collections.unmodifiableSet
– Collections.unmodifiableMap
这种包装器得到的结果是不可变的:只能看
但是这种“不可变”是在运行阶段获得的,编译阶段 无法据此进行静态检查
所以如果对这种类型变量来 sort() ,java不会warn ,会在运行的时候报 exception
ADT
Spec
除非spec的后置条件中有说明,否则方法不应该修改输入参数
spec变强:更放松的前置条件+更严格的后置条件
越强的规约,意味着implementer的自由度和责任越重,而client的 责任越轻。
Diagramming specifications
某个具体实现, 若满足规约,则落在其范围内;否则,在其之外。
更强的规约,表达为更小的区域
ADT operations
creator : t* → T
producer : T+, t* → T
observer : T+, t* → t
mutator : T+, t* → void | t | T
注:
Each T is the abstract type itself
Each t is some other type.
举例:
操作 | 类型 |
---|---|
Integer.valueOf() | Creator |
String.toUpperCase() | Producer |
BufferedReader.readLine() | Mutator !!! |
Map.keySet() | Observer !!! |
how to establish invariants
established by creators and producers(创建要合法,checkRep)
preserved by mutator and observers(修改要合法,checkRep)
no representation exposure occurs (没有表示暴漏)
Override & Overload
重写(Override)
即外壳不变,核心重写!
重载(Overload)
方法名字相同,而参数不同,
相同/不同的返回值类型
相同/不同的public/private/protected
区别:
Override 在运行阶段时决定执行哪个方法 (dynamic type checking)
Overload 在编译阶段时决定执行哪个方法 (static type checking)
Equality of ADT
Equality of Immutable Types
看AF: AF映射到同样的结果,则等价
看observation:站在外部观察者角度,对两个对象调用任何相同的操作,都会得到相同的结果,则认为这 两个对象是等价的。
观察等价性和行为等价性对Immutable Types来说等价
Equality of mutable Types
行为等价性:调用对象的任何方法都展示出一致的结果(很严格);接近于==;object的equals就是按照行为等价性
java中 list,set实现观察等价性(只需要里面装的东西,属性相同,即等价)
Equality contract
用“是否为等价关系”检验你的equals()是否正确,如下:
Reflexive – every object is equal to itself
Symmetric – if a.equals(b) then b.equals(a)
Transitive – if a.equals(b) and b.equals(c), then a.equals(c)
Consistent– equal objects stay equal unless mutated
“Non-null” – a.equals(null) returns false
hashcode contract
等价的对象,hashCode()必须相同
So
So immutable types must override both equals() and hashCode() .
So mutable types should not override equals() and hashCode() at all,
Autoboxing and Equality
观察下面现象
1 | Map<String,Integer> a=new HashMap<>(); |
1 | Map<String,Integer> a=new HashMap<>(); |
为什么!
-128~127,java内存中提前new好了,每次自动Autoboxing 的时候都去指向它们。
不是Autoboxing,当然不会这样
1 | Map<String,Integer> a=new HashMap<>(); |