【软件构造】软件构造复习总结2-第三章部分
第三章内容较多,同时也是软件构造的重点部分。
第三章: 一、数据类型与类型检验 1.基本数据类型(小写开头如int)和对象数据类型(大写开头如String): 基本数据类型为immutable,在栈中分配内存,对象数据类型在堆中分配内存。 基本数据类型可以包装成对象数据类型:如int->Integer, 有以下例子: List l = new ArrayList(); l.add(1);//虽然1不是Integer,但会完成自动转换 l.add(Integer.valueOf(1));//自动转换 2.静态类型检查和动态类型检查: 静态(主要关于类型):语法,类/函数名,参数数目,参数类型,返回值类型。 动态(主要关于值):非法参数值,非法返回值,越界,空指针。 3.Mutability and Immutability: a.Immutability:一旦创建,其值不变,可以用final声明。 对于final:final类无法派生子类;final方法无法被子类override;final变量无法改变值/引用。 b.Mutability:可以用方法改变其值/引用。 c.String:String是一个不可变的数据类型。 StringBuilder:StringBuilder是一个可变的数据类型。 eg1. 快照图(不可变用双圈表示):对于不可变的数据类型,要在末尾添加b,只能通过创建一个新的并改变其在内存中指向。 eg2. 快照图(可变用一个圈表示):对于可变的数据类型,要在末尾添加b,只需直接更改其值即可。 eg3.(在上两个例子的基础上) 快照图:对于前两行,第一行,将s赋给t,是t指向s指向的地方,第二行,若要加c,需创建一个新的,再令t指向新的,s的只想不变。对于后两行,第一行同理,第二行加c后,直接在原来位置修改其值,但sb所指向的内容也变成了abc。 例.
String s = " hello"; s += " world "; s.trim(); System.out.println(s);打印: 前后有空格。 快照图:因String为不可变,所以创建了新的,但没有引用,只会被回收。
String s = " hello"; s += " world "; s = s.trim(); System.out.println(s);打印: 前后无空格。这里被s指向了,所以结果为想要的。 d.可变存在的风险:客户端可能修改数据。 可以使用防御式拷贝进行返回。即创建一个新的返回对象返回。即使修改也不会对原有数据造成影响。 4.快照图:描述程序运行时的内部状态。 不可变对象:双线椭圆。 不可变引用:双线箭头。(final int n = 5;) eg.
String s1 = new String("abc"); List<String> list = new ArrayList<String>(); list.add(s1); s1 = s1.concat("d"); System.out.println(list.get(0)); String s2 = s1.concat("e"); list.set(0, s2); System.out.println(list.get(0));打印: 快照图:list指向ArrayList对象,s1一开始指向abc,第三行加入后,ArrayList第0位指向abc,s1加d后,由于s1是不可变,所以要创建一个新的进行指向,但ArrayList第0位指向没变,所以第一个打印abc, 由于ArrayList是可变的,第0位指向了s2指向的abcde,所以打印abcde。 5.Iterator:迭代器(mutable) 两种方法迭代: a. b.其中.next()是一个mutator方法。每次迭代自动将index+1. 6.常用不可变与可变: 基本类型及其封装类不可变。 List,Set,Map是可变的,可以用Collections.unmodifiedList()等防止修改 可以用List.of创建不可变集合,如: List a = List.of(“lion”, “tiger”, “bear”); 二、设计规约 1.前置条件:客户端需要满足的条件。 2.后置条件:开发者必须满足的条件。 3.spec格式:如: 4.除非后置条件声明过,否则方法尽量不改变传入参数。 5.更强的spec:更弱的前置条件(要求的更少),更强的后置条件(承诺的更多)。 后置条件比较时,要以同一强的前置条件为前提,进行比较,如: 三、抽象数据类型 (ADT) 1.可变数据类型:提供了可改变其内部数据的值的操作。 2.不变数据类型: 其操作不改变内部值,而是构造新的对象。 3.Creators(构造器),Producers(生产器),Observers(观察器),Mutators(变值器)。 Producers(生产器):从老的object生成一个新的object。 Mutator(变值器):一般返回void,也有可能其他。 4.表示独立性:client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端。 5.ADT的测试: 测试creators, producers, and mutators:调用observers来观察这些 operations的结果是否满足spec; 测试observers:调用creators, producers, and mutators等方法产生或改变对象,来看结果是否正确。 6.保持不变性和避免表示泄漏,是ADT最重要的一个Invariant。 7.RI/AF/Safety from rep exposure: RI:规定合法值 AF:解释合法值(映射) Safety from rep exposure:如何防止表示泄露的问题。 checkrep():根据RI写,在所有可能改变rep的方法上都要加上。 例: 8.重点是良好的不变量,避免表示泄露。防止受到客户端的影响。 四、面向对象的编程 1.静态方法不需要与类的实例相关联使用,而实例方法需要在对象上调用。 如: 2.接口(Interface):一个接口可以有多个实现,一个类可以实现多个接口,接口之间可继承。 3.静态工厂方法:在接口中返回具体实现类。如: (FastMyString为MyString的一个实现类)。 客户端: 4.重载(Overload)需要注意的: 右边箭头根据Animal为输入参数调用函数。 5.泛型编程:如: 6.equals,hashcode,toString: equals: hashCode: 五、ADT和OOP中的“等价性” 1.==与.equals():==是引用等价性,.equals是对象等价性。一般在immutable中区分,引用等价性即在内存中的引用是否相同,.equals即根据AF映射关系是否映射相同。 2.若两个对象.equals判断相等,则必须有相同的hashCode。 3.a.equals(null)返回false: 如果a不为空,则返回false,若a为空,则会抛出空指针异常。
List<Integer> list = null; System.out.println(list.equals(null));控制台: 如果用==null,则会返回ture/false:
List<Integer> list = null; System.out.println(list==null);控制台: 4.观察等价性和行为等价性:对于Mutable类型,观察等价性类比于.equals(),行为等价性类比于==。(List中的.equals()为观察等价性) 对于可变类型一般不重写equals()和hashCode(),一般实现行为等价性。
/***********************************************************************************/ 以上即为软件构造复习总结2-第三章部分。
