第三章:抽象数据类型(ADT)和面向对象编程(OOP)
第一节:数据类型和数据类型检查
问题一:java中数据类型的分类
- 基本数据类型(primitive types)
- 对象数据类型(object types)
二者不比较:先下图
(*基本数据类型 只有值 没有ID 的意思是:若 int a=1;int b =1;则a和b指向的是同一存储空间的值“1”;而对象数据类型a 和 b就指向两个不同的存储空间)
(*注意基本数据类型是不可变的;对象数据类型有的是可变的 有的是不可变的)
- 可以将基本数据类型包装为对象类型(通常是在定义集合类型的时候使用它们、一般情况下,尽量避免使用、 一般可以自动转换)
问题二: 静态类型(Static Typing)与动态类型(Dynamic Typing)
区别:静态类型语言在编译阶段进行类型检查
动态类型语言在运行阶段进行类型检查
问题三:类型检查
静态类型检查:可在编译阶段发现错误,避免了将错误带入到运行阶段,可提高程序正确性/健壮性
静态类型检查的错误类型:语法错误、类名/函数名错误、参数数目错误、参数类型错误、返回值类型错误
动态类型检查:在运行阶段进行检查
动态类型检查的错误类型:非法的参数值、非法的返回值、越界、空指针
- 静态检查:关于“类型”的检查,不考虑值;
- 动态检查:关于“值”的检查
- java采取的是静态类型检查
- Python采取的是动态类型检查
问题四:可变性(Mutability)与不变性(Immutability) 变量
***改变一个变量与改变一个变量的值 的区别:
- 改变一个变量:将该变量指向另一个值的存储空间
- 改变一个变量的值:将该变量当前指向的值的存储空间中写入一个新的值。
1.Immutability 不变性
- 不变数据类型:
- 对基本数据类型来说:一旦被创建,其值不能改变
- 对引用数据类型来说(数组,类,字符串):一旦确定其指向的对象,(对象的值)不能再被改变
- 如果想创建一个不可改变的数据 用 final 关键字(final类无法派生子类、final变量无法改变值/引用、final方法无法被子类重写)
- 不变对象:一旦被创建,始终指向同一个值/引用;可变对象:拥有方法可以修改自己的值/引用
*例1:(String 是不可变的 引用型 数据类型)
(因为String是不可变的,一旦被创建,String对象的值是不能改变的,为了在字符串后面加一些字符,需要在创建一个新的String类型的对象(*注意:s不是对象,只是对象的引用))
(****注意:此处不可变的 是指String类型的object 不可变,而String的引用s是可变的,s所引的对象“a”是不可变的;即可以改变s变量,不能改变s变量的值!)
*例2:(StringBuilder 是可变的 引用型 数据类型)
(因为StringBuilder 是可变的,所以这个类有方法来改变这个对象的值)
*例1与例2的结合(找差异):
(由于s 和 t 都是String 引用类型的数据类型,都是不可改变的,当将s引用的地址赋给t时,二者将指向同一位置,所以当t引用的值改变时,由于String类型是不可变的,只能创建一个新的String类型的对象来让 t 引用)
(由于sb 和 tb 都是StringBuilder 引用类型的数据类型,是可以改变的,当将sb引用的地址赋给tb时,二者将指向同一位置,所以当tb引用的值改变时,由于StringBuilder类型是可变的,所以改变了t引用的对象的值,自然也改变了sb引用的对象的值)
解决办法:(防御性编程:通过防御式拷贝,给客户端返回一个全新的Date对象(返回一个new的对象) )
- 不变性与可变性利弊:
不可变性:使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收);不可变类型更“安全”,在其他质量指标上表现更好。
可变性:可变类型最少化拷贝以提高效率;可获得更好的性能,也适合于在多个模块之间共享数据;可变性数据类型造成的错误非常难于跟踪和发现。
问题五:用Snapshot视图理解可变性与不可变性
基本类型的值:Primitive values are represented by bare constants. The incoming arrow isa reference to the value from a variable or an object field.
(Snapshot视图的描绘方式)
对象类型的值:An object value is a circle labeled by its type. When we want to show more detail, we write field names inside it, witharrows pointing out to their values. For still more detail, the fields caninclude their declared types.
(snapshot视图的描绘方式)
- String s = “a”;不可变对象,但引用是可变的
String s = “ab”;(改变了s 的引用)
(不可变对象:用双线椭圆)
- 若要将上面的s的引用 变成不可变,可用 final 关键字
(不可变的引用:用双线箭头)
**例:①int a = 5(可变的引用,不可变的值)
②StringBuilder sb(可变的引用,可变的值)
③final StringBuilder sb (不可变的引用,可变的值)
④final String a(不可变的引用,不可变的值)
**例:
用snapshot视图描绘:
(因为用final定义了可变类型StringBuilder,所以他引用是可变的,值是不可变的)
***例:
用snapshot视图描绘:
(List是可变数据类型,String是不可变数据类型。注意虽然List是可变的,但其内部的元素String是不可变的!)
问题六:Iterator as a mutable type 迭代器是可变的数据类型
snapshot表示:
***例:
结果:
snapshot描绘:
(因为迭代器是可变的类型,所以list的值可以改变,但因为list的引用是双线,所以引用不能改变)
所以下面这段代码同样会犯上面的错误:↓↓↓
改正方法如下即可避免错误:↓↓↓
问题七:其他实用的不可变的数据类型
- 基本类型及其封装对象类型都是不可变的
- java中实现集合类的数据类型都是可变的,如:List,Set,Map,ArrayList,HashMap