软件构造第三章复习

3.1数据类型与类型检验

一.编程语言中的数据类型

以Java为例,可以分为以下两类
(1).基本数据类型:int,double,boolean,long,char…(不可变数据类型)
(2).对象数据类型:String,BigIntegar…(有的可变,有的不可变)
如果要将基本数据类型包装为对象数据类型,首字母大写即可。
如:boolean:基本数据类型;Boolean:对象数据类型

二.静态类型语言和动态类型语言

静态类型语言:在编译阶段进行检查(如Eclipse)
动态类型语言:在运行阶段进行检查(如Python)

静态检查:在编译阶段进行检查的东西
如:语法错误,类/函数名错误,参数数目错误,参数/返回值类型错误…
动态检查:在运行阶段进行检查的东西
如:非法的参数值,非法的返回值,越界,空指针…

注:(1).进行什么类型的检查与是什么类型的语言是无关的
(2).静态检查一般检查类型,而动态检查一般检查值

三.可变性与不变性

改变一个变量:将该变量指向另一个值的存储空间
改变一个变量的值:将该变量当前指向的值的存储空间中写入一个新的值

可变数据类型:被创建后,其值可以发生变化,但地址空间不变(如StringBuilder)
不可变数据类型:被创建后,其值不能够发生变化(如String)

可变引用:可以指向不同的地址空间(但是这些地址空间的值可能是不变的)
不可变引用:只能指向确定的地址空间(但是这个地址空间的值可能是可变的)

补:在创建变量时采用final作为限定词,会使得这个变量不可被重新赋值

四.代码快照图

基本数据类型:箭头指向该数据
对象数据类型:箭头指向椭圆(里面是这个对象)
不可变对象:双线椭圆
不可变引用:双线箭头

五.一些常见的对象数据类型(重点)

1.List(不定长的数组)

初始化:List<数据类型>list = new Arraylist<>()
数组长度:list.size()
数组索引:list.get(2) 返回数组中下标为2的元素
数组赋值:list.set(2,0) 给下标为2的元素赋值为0

2.Set(无序的集合,不允许有重复值)

初始化:Set<数据类型>set = new Hashset<>()
判定e是否在某一个set s里:s.contains(e)
判定S2是不是S1的子集:S1.containsAll(S2)

3.Map(一个Key-Value键值对)

初始化:Map<数据类型,数据类型>turtles = new Hashmap<>()
将key放入val的子类中:map.put(key,val)
读取key对应的val值:map.get(key)

4.显式迭代器的使用(这里以list为例)

List< Integar >list = new ArrayList<>();
Iterator its = list.Iterator();
while(its.hasNext()){
Integar it = its.hasNext();
system.out.println(it);
}

5.基本数据类型的封装

List封装为不可变:Collections.unmodifiableList();
Set封装为不可变:Collections.unmodifiableSet();
Map封装为不可变:Collections.unmodifiableLMap();

3.2设计规约

一.编程中的函数语言与方法

静态方法(有static的):属于同一个类的,可以直接调用
非静态方法(没有static的):在使用之前需要new一个新的对象才能使用
注:参数的设置与返回值类型与C语言是相同的

二.规约的结构:前置条件与后置条件(重点)

前置条件:对客户端的约束
后置条件:对开发者的约束
书面语言:前置条件:requires; 后置条件:effects
Java语言:前置条件:@param; 后置条件:@return
规约的基本格式:
/**
*…(一些具体说明)
*@param…(前置条件)
*@return…(后置条件)
*/

三.设计规约(重点)

当S2的前置条件比S1弱,且后置条件比S1强时,称规约强度S2>S1(S2可替代S1)
(能够比较一个规约能否替代另一个规约即可)
欠定规约:同一个输入可能有多个输出
非确定规约:同一个输入,多次输出的结果可能不同

3.3抽象数据类型(ADT)

一.数据分类

1.构造器(creator):从无到有,一般是构造函数或者创建静态函数
如:new ArrayList()–创建一个新的ArrayList数组
2.生产器(producer):从旧到新
如:String.concat()–连接两个字符串生成新的字符串
3.观察器(observer):返回新的数据类型
如:List.size()–返回数组长度
4.变值器(mutator):改变对象属性
如:Set.add()–向集合内添加数,添加成功返回true,添加失败返回false
注:若变值器返回void类型,则必然改变了对象的某些属性

二.测试ADT

(1).测试creator,producer,mutator时,调用observer来进行观察,看结果是否满足spoc
(2).测试observer时,调用creator,producer,mutator来产生和改变对象,看结果是否正确

三.ADT的表示不变量

1.ADT的不变量

关键:保持不变性和避免考试泄露
(1).不要将可变对象引入到对象中–采用防御式拷贝
(2).不要将可变对象直接return到外部–采用防御式拷贝

2.表示不变量(RI)和抽象函数(AF)

R:表示值构成的空间:实现者看到和使用的值
I:抽象值构成的空间:用户(client)看到和使用的值
补:R->A一定是满射,但未必是单射
AF:R->A的抽象函数
RI:表示R中可以映射到A的值,即一个所有合法值的集合,也称为不变性RI

3.4ADT的具体实现技术:OOP

OOP(Object-oriented Programmihng):面向对象编程

一.对象(Object)和类(Class)的定义

Object(对象):在生活中真实存在的,针对对象进行的操作成为method或者function
Class(类):对对象进行的抽象,现实中是不存在的,是一个概念(一般是名字+成员变量+方法)
注:(1).静态方法可以通过类的名字直接调用,而当变量或方法是属于对象的时候,需要先创建一个实例后再进行调用(有static的可以直接调用,没有static的需要先创建对象)
(2).静态方法无法直接调用非静态成员

二.接口和枚举类型

接口只有定义没有实现,需要通过类来实现;接口之间可以继承和扩展

接口继承关键字:implements
创建接口关键字:interface
例:public interface Complex{…}
class OrdinaryComplex implements Complex{…}
补:(1).接口中不允许有构造器
(2).接口中的功能要尽可能通用,否则可以放在各个具体类中实现
(3).在接口中的方法,继承之后一定要分别实现

三.信息隐藏和封装

关键:将不应该暴露给客户端的信息隐藏起来,保证安全性
对四种作用域的总结:
在这里插入图片描述

四.继承和重写

1.继承:代码重用

如:class A extends B(类A继承类B),B中的public,protected变量被继承,但private不可继承
严格继承:子类中只能添加新的方法,无法重写超类中的方法
对final的一些使用:
(1).对一个变量(field)使用final:这个变量不可以再次被初始化
(2).对一个方法(method)使用final:这个方法不可被重写
(3).对一个类(class)使用final:这个类不可被继承

2.重写

重写的函数有相同的名称,相同的签名(内部参数),相同的返回值。
(1).若子类一部分继承父类,一部分重写,则继承的父类需要先写
(2).在重写函数时,前面加上一个@override,让编译器进行检查

3.extends与implements的区别

extends用于继承一个类,后面跟父类的名字,继承只能继承一个类
implement用于实现一个接口,接口可以有多个
如:class A extends B implements C,D,E(类A继承类B并且继承C,D,E三个接口)

4.抽象类(Abstract class)

若一个类中至少含有一个抽象方法,则可称为抽象类
如public abstract class …(定义一个抽象类)
(1).抽象类不允许实例化,即不能用new生成对象
(2).继承某个抽象类的子类在实例化时,所有父类中的抽象方法必须已经实现

5.多态,子类型,重载

特殊多态:一个方法可以有多个同名的实现(方法重载)
参数化多态:一个类型名字可以代表多个类型
子类型多态:一个变量名字可以代表多个类的实例
重载是一种静态多态,编译阶段要决定具体执行哪个方法
重载的规则:
(1).必须有不同的参数列表(参数数目或者参数类型不同)
(2).返回值,作用域,抛出异常不做要求
(3).可以在一个类中重载,也可以在子类中重载

特殊多态(重载)

例:

class Animal{
	public void eat(){
	system.out.println("1");
	}
}
class House extends Animal{
	public void eat(String food){
		system.out.println("2"+ food);
	} 
	public void eat(){
		system.out.println("3");
	}
}

//运行以下代码并判断输出的是什么
1.Animal a = new Animal();
  a.eat();
2.Horse h = new Horse();
  h.eat();  
3.Animal ah = new Horse();
  ah.eat();
4.Horse he = new Horse();
  he.eat("Apples");
5.Animal a2 = new Animal();
  a2.eat("Carrots");
6.Animal ah2 = new Horse();
  ah2.eat("Carrots");

运行结果如下
1.输出:1
2.输出:3
3.输出:3
4.输出:2Apples
5.编译错误
6.编译错误

很显然123是重写,456是重载
重写考察的是创建实例的类型,根据创建的实例选择调用的函数。
以3为例:Animal ah = new Horse();创建的是Horse实例,所以调用Horse的方法,最后输出3。
重载是在编译阶段进行检查的,运行时取决于变量类型是什么
以6为例:Animal ah2 = new Horse();变量类型是Animal,所以调用Animal的方法,由于Animal中没有带参数的eat方法,所以发生编译错误。

参数多态性(用统一的类型表达多种类型)–泛型编程

例如:List< T >,T可以是int,string,person…,但在使用前需要确定具体类型
泛型接口分为泛型实现类和非泛型实现类,取决于是否支持泛型拓展
注:不允许创建泛型数组

子类型多态性(子类型的规约不能弱化超类型的规约)

子类型中的方法比父类型必须只多不少(子类型拥有父类型中的所有方法)
一些常见的重写方法(参数为Object类型的)
(1).equals()–判定两个Object是否“相等”
(2).hashcode()–判断两个对象是否"相等"
(3).toString()–打印字符串

3.5ADT与OOP中的等价性

一.等价关系

在数学中,等价关系要满足以下三点:自反性,传递性,等价性
自反性:E(t,t)
对称性:E(t,u)=>E(u,t)
传递性:E(t,u)且E(u,v)=>E(t,v)

二.三种考虑相等的方法

在ADT中,考虑抽象函数AF。若AF(a)==AF(b),则a与b等价
从外部角度观察,如果对两个对象调用任何操作都能得到相同的结果,则这两个对象等价

三.equals()与 ==

equals:对象等价性–判断对象内容是否相等
==:引用等价性–判断内存中使用的是否是同一个地址空间
对于基本数据类型用第二个,对于对象数据类型则用第一个

四.instanceof的一些用法

instanceof是一个操作符,不是方法名,用于判断某个对象是否是特定类型(或其子类型),若不存在任何继承关系,则会返回编译错误
instanceof是动态类型检查,除了用于实现equals()方法时,尽量不要使用instanceof

五.equals()契约

(1).等价关系
(2).当指定对象不变时,调用equals()得到的结果是相同的
(3).对一个非空的x,x.equals(null)返回false
(4).对于“相等”的对象,其hashcode()的结果是一致的

六.可变类型的等价性

观察等价性:在不改变状态的情况下,两个mutable对象看起来是否一致
行为等价性:调用对象的任何方法都展示出一样的结果
注:(1).对可变类型,实现行为等价性即可
(2).对可变类型,无需重写equals()和hashcode(),直接继承Object中的方法即可

七.装箱操作和相等

例:

Integar x = new Integar(3);
Integar y = new Integar(3);
x.equals(y);//操作1
x == y;//操作2
int(x) == int(y);//操作3

操作1返回结果为:true,因为对象的值相同
操作2返回结果为:false,因为x和y的地址不同
操作3返回结果为:true,因为基本数据类型进行比较是判断值是否相等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值