抽象数据类型+面向对象编程基础
1.基本数据类型、引用数据类型
基本数据类型
1、在基本数据类型中,除了boolean类型所占长度与平台有关外,其他数据类型长度都是与平台无关的。比如,int永远占4个字节(1 Byte = 8 bit)。
2、void不是基本数据类型
3、基本数据类型的默认值仅在作为类中属性时生效,在方法内部必须先对基本数据类型变量赋值后才能使用,否则编译不通过。
引用数据类型
引用类型(reference type)指向一个对象,不是原始值,指向对象的变量是引用变量。
在java里面除去基本数据类型的其它类型都是引用数据类型,自己定义的class类都是引用类型,可以像基本类型一样使用。
引用类型常见的有:String,StringBuffer,ArrayList,HashSet,HashMap等。
如果要对比两个对象是否相同,则需要使用equals()方法,但有一点需要注意:equals()方法的默认行为是比较引用。如果是你自己写的类,你应该为它重写equals()来比较对象的内容。大多数Java类库都实现了比较对象内容的equals()方法。
两者比较
2.类型检查
静态类型检查:编译时可在编译阶段发现错误,避免了将错误带入到运行阶段,可提高程序正确性/健壮性
关于“类型”的检查,不考虑值
①语法错误
②类名、函数名错误
③参数数目错误
④参数类型错误
⑤返回值类型错误
⑥其他情况,如变量可能没有初始化,在一些条件分支里声明的变量无法在分支外使用等等
动态类型检查:运行时
关于“值”的检查
①非法的参数值,如除零错误
②非法的返回值,如返回的具体值不能被转换成对应的类型
③越界
④空指针
3.可变对象、不可变对象、final关键字
不变对象:
如String,一旦被创建,始终指向同一个值/引用。如果编译器无法确定final变量不会改变,就提示错误,这也是静态类型检查的一部分。
不提供可改变其内部数据的值的操作。
可变对象:
如StringBuilder,拥有方法可以修改自己的值/引用。
提供了可改变其内部数据的值的操作。
比较:
①使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收) ,使用可变类型会减少拷贝
②使用可变数据类型,可以提高性能,方便在多个模块之间共享数据。
③使用不可变数据类型,更容易达到安全要求。
final关键字:
①修饰类当用final去修饰一个类的时候,表示这个类不能被继承。
注意:
a. 被final修饰的类,final类中的成员变量可以根据自己的实际需要设计为fianl。
b. final类中的成员方法都会被隐式的指定为final方法。
②被final修饰的方法不能被重写。
注意:
a. 一个类的private方法会隐式的被指定为final方法。
b. 如果父类中有final修饰的方法,那么子类不能去重写。
③修饰局部变量
注意:
a. 必须要赋初始值,而且是只能初始化一次。
④修饰成员变量
注意:
a. 必须初始化值。
b. 被fianl修饰的成员变量赋值,有两种方式:1、直接赋值 2、全部在构造方法中赋初值。
c. 如果修饰的成员变量是基本类型,则表示这个变量的值不能改变。
d. 如果修饰的成员变量是一个引用类型,则是说这个引用的地址的值不能修改,但是这个引用所指向的对象里面的内容还是可以改变
4.防御式拷贝
返回可变类型对象时,为了防止该对象在别处被修改,创建一个新的对象,并复制原来的对象的各项属性,并返回这个复制后的新对象。
5.snapshot diagram
①基本类型的值
②对象类型的值
③不可变对象:双线椭圆
④可变对象
⑤不可变的引用:双线箭头
6.spec、precondition、postcondition
spec:
写在方法之前,只讨论输入输出的数据类型、功能和正确性、性能等,不讨论具体实现
应该包含前置条件、后置条件、和函数期望完成的行为。
@param 输入参数的含义
@return 返回参数的含义
@throws 抛出异常的含义
前置条件:
对客户端的约束,在使用方法时必须满足的条件
后置条件:
对开发者的约束,方法结束时必须满足的条件
前置条件满足,则后置条件必须满足。
前置条件不满足,则方法可做任何事情。
在涉及到可变类型等情况时,不要只依靠客户端和开发者的行为,要在规约里限定住。
7.行为等价性
定义:两个函数是否可相互替换?
①单纯的看实现代码,并不足以判定不同的implmentation是否是“行为等价的”
②需要根据spec判定行为等价性
③在编写代码之前先要确定spec如何形成、撰写。
8.spec强度
spec变强:更放松的前置条件,更严格的后置条件。
意味着实现更难,使用更轻松。
spec强的函数可以替换spec弱的。
9.ADT的四种基本操作
①构造器:t* -> T
创建对象,可能为静态函数或构造函数
②变值器:T+,t* -> void|t|T
通常返回void,但改变了内部的某些状态。
也可能返回非空类型。
③观察器:T+,t* -> t
返回内部某些状态
④生产器:T+,t* -> T
从旧对象中构建新对象。
10.表示独立性
内部实现如何变化,不影响客户端使用,也不影响规约。
如果没写前置、后置条件,就不能改变内部表示。
11.AF、RI
RI:
不变量,程序的某种“特性”,这种特性无论在什么时候都需要成立。
表示不变量,表示空间集合中的一个子集,包含了所有合法的表示值,或者说对于合法表示的描述。
和客户端无关,由ADT自身负责维持不变量。
如果出现了表示泄露,就不能保证不变量,也不能保证独立性。
ADT要保证不变性、不产生表示泄露。
checkRep()表示检查表示不变量的函数,要保证ADT的四个操作都要执行这个检查函数,并且在"null"的情况下不能通过检查。
R:表示空间,实际存入ADT中真实的值
A:抽象空间,使用ADT的客户端看到和使用的值。
AF:R→A的一个映射关系,是R中的值在A中的解释。
这个映射是满射,但未必是单射、双射,并且R中的一些值可能是非法的,在A中无对应。
同样的R、RI,但可能有不同的AF,即解释不同。
12.表示泄露
把R空间的东西泄露给了客户端
一旦泄露(将引用传递到客户端),内部表示可能被意外更改,无法保证RI
13.接口、抽象类、类
14.访问控制符:public,protected,default,private
①私有权限 private
private可以修饰数据成员,构造方法,方法成员,不能修饰类(此处指外部类,不考虑内部类)。被private修饰的成员,只能在定义它们的类中使用,在 其他类中不能调用。
②默认权限 (default)
类,数据成员,构造方法,方法成员,都能够使用默认权限,即不写任何关键字。默认权限即同包权限,同包权限的元素只能在定义它们的类中,以及同包 的类中被调用。
③受保护权限protected
protected可以修饰数据成员,构造方法,方法成员,不能修饰类(此处指外部类,不考虑内部类)。被protected修饰的成员,能在定义它们的类中,同包(最后一次重写该函数的位置)的类中被调用。如果有不同包的类想调用它们,那么这个类必须是定义它们的类的子孙类。
④公共权限 public
public可以修饰类,数据成员,构造方法,方法成员。被public修饰的成员 ,可以在任何一个类中被调用,不管同包或不同包,是权限最大的一个修饰符。
有关Java语言的修饰符,需要注意的问题有如下几个:
①并不是每个修饰符都可以修饰类(指外部类),只有public和default可 以。
②所有修饰符都可以修饰数据成员,方法成员,构造方法。
③为了代码安全起见,修饰符不要尽量使用权限大的,而是适用即可。比如 ,数据成员,如果没有特殊需要,尽可能用private。
④修饰符修饰的是“被访问”的权限。