【软件构造】课件精译(五)数据类型与类型检验

前言

因为最近开始继续做项目了,课余时间比较紧张。第一篇的前言虽然说要选重要部分翻译,但事实上目前为止几乎是全部翻译,所以以后的内容可能会写的敷衍一些,排版标号也会比较简单,挑一些个人感觉有价值的东西放上来,还请见谅。

本章说明

从这一章起,课程正式以Java为编程语言讲解一切软件开发的具体事项,不再是前几章那样的软件构造理论。本章还是以Java语法为主,但是值得注意或者易混淆的地方还是很多。
本章的题目是“数据类型与类型检验”,涉及数据类型、静态和动态类型检测、易变性和易变对象、不变形和类似于C++ STL的一些Java类和Collections。总的来说都是数据类型方便的内容。

正文

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

类型与变量
类型是一组值,以及可以对这些值执行的操作。在Java中分为基本数据类型和对象数据,通常基本数据类型小写开始,对象数据类型大写开始。
对于基本数据类型,按照值来区分,而对象数据类型则不是,即使值相同也未必相等,就像String不能用双等号,而需要用.equal来判断是否相等。
对象类型的层级关系
基本数据类型的包装类
Boolean, Integer, Short, Long, Character, Float, Double
实际上就是把基本数据类型封装为对象,但尽可能少用。另外在使用一些像List这样类时,不允许List,需要List list = new ArrayList();
在这个过程,list.add(1)会被自动转换为list.add(Integer.valueOf(1)),会降低效率。
操作
重载运算符和操作
(重载在之后的章节会具体讨论

二、静态、动态数据类型

Java是一个静态数据类型语言,在编译时需要知道所有变量的类型,编译器可以推断所有表达式的 类型。相对而言的Python就是动态数据类型语言,变量的类型在运行过程是可以变化的。

三、类型检查

静态检查和动态检查
静态类型检测是在程序运行前,比如IDE就可以做这样的工作,动态类型检测是在代码运行过程中。
类型不匹配
类型转换
静态检查
动态检查
例如除以零、索引越界、空对象(类似C语言的空指针)
很多变量的值只有运行时才知道,这就需要用到动态检查。
基本数据类型不是真正的数字

四、可变性与不可变性

赋值
改变变量和改变它的值
简单的说前者是改变变量的指向,比如test = new ArraryList()就是将这个类指向了堆上新的位置,而test.add(“Good”)就是在修改它的值。用课件上的话来说,“对变量赋值是在改变变 量的指向,指向不同的值 ”,“改变可变变量的内容时 ,是在改变变量内部内容的引用 ”。
不变性
final关键字对不可变引用提供了静态检查的支持,建议利用final来声明方法的参数和局部变量。
final class表示它不能被继承,final method表示它不能被重写。
不可变的对象:一旦创建,总是表示相同值。
可变的对象:它们的方法可以修改对象的值。
String
String是一个不可变类,总是表示相同的值,而像字符串连接或者重新赋值这样的操作,事实上是修改了其指向。
在这里插入图片描述
StringBuilder
StringBuilder是一个可变类,含有修改、删除其某个字符的方法。
在这里插入图片描述
当只有一个引用时,两者的使用区别不大,当有多个引用时,二者的区别很大。下图就可以很好的解释,如果sb和tb指向同一个StringBuilder,一旦一个修改,另一个也会修改,而如果是String,一个修改会指向新的变量,而另一个保持不变。
在这里插入图片描述
可变类型的优点
使用不可变字符串会产生很多临时副本,而StringBuilder就是用来减少副本的。
在这里插入图片描述
可变类型还可以方便程序间的数据共享,例如全局变量,当然全局变量也有缺点。
变化的风险
可变类型会引发更多风险:
Example #1
在这里插入图片描述
因为之前调用了sumAbsolute方法导致其值被改变了,所以sum方法也得不到想要的结果了。所以说,传递可变对象容易产生潜在错误,且难以跟踪。
Example #2
在这里插入图片描述
分析可知,本来只是用startOfSpring做个参照,但是因为传递的引用,所以partyDate的修改也修改了groundhogAnswer,影响了成员变量的值。
问题的原因在于Date是可变类型,可以用java.time包里的其他不变类代替,如: LocalDateTime , Instant 等。
另外,采用不可变类型,可通 过内存共享相同的值,降低复制带来的内存空间占用,并且不可变类无需防御性拷贝。
只在局部使用或者只有一个引用时,可变类型的使用是安全的,对可变类型的多个引用(别名)是带来风险的原因。
防御性拷贝
在这里插入图片描述
在这里插入图片描述
可以看到,因为Date是可变类,get到以后仍然修改了private的值,或者来自的构造元素的变化也修改了private的值,所以可变类的使用很容易造成风险。

五、关系快照图(Snapshot diagram )

关系快照图描述了程序运行过程中的内部状态,例如栈(包括上面的方法和变量)、堆(存在的对象)
通常对象被圈起来,而原始类型直接指过去,如图:
在这里插入图片描述
在这里插入图片描述
在关系快照图中,final修饰的变量用双箭头表示。如果final修饰可变类型,实际上是指向可变值的不可变引用( 引用不可变,值可变) 。

六、复杂数据类型:Arrays和Collections

Array
int[] a = new int[100];
操作:索引、赋值、求长度(.length)
List
List list = new ArrayList();
操作:get,set,size
注意:List是一个接口,并且其成员必须是对象数据类型。
迭代
Set
集合类似于数学里的集合,无序,不可重复。
常用方法有:contain,containsAll(判断是不是子集),removeAll(从一个集合中删除一个集合)
同样,Set也是一个抽象接口。
Map
常用方法:put,get,containsKey,remove
Map也是一个抽象接口,常用的有HashMap。
通过Array构建list
Arrays.asList(new String[] { “a”, “b”, “c” })
声明List,Set和Map变量
当添加一个item时 ,编译器执行静态检查,确保只添加合适类型的item。
创建List,Set和Map变量
List,Set和Map作为接口, 定义了类型的工作方式,但不提供实现代码。 所以用户有权在不同情况下选择不同的实现。
一些实现:
List: ArrayList and LinkedList
Set: HashSet
Map: HashMap

Java Collection
在这里插入图片描述
迭代

List<String> cities = new ArrayList<>(); 
Set<Integer> numbers = new HashSet<>(); 
Map<String,Turtle> turtles = new HashMap<>();

for (String city : cities) { 
	System.out.println(city); 
}
for (int num : numbers) {
	System.out.println(num); 
}
for (int ii = 0; ii < cities.size(); ii++) {
	System.out.println(cities.get(ii)); 
}
for (String key : turtles.keySet()) {
	System.out.println(key + ": " + turtles.get(key)); 
}

迭代器是一个对象,它遍历一组 元素并逐个返回元素。 遍历时默认调用迭代器。
迭代器有两个方法,next() 返回下一个元素,hasNext()测试是否迭代到了最后。
在这里插入图片描述

补充:Mutator Methods就是指set方法,而Accessor Methods指get方法。

一个ArrayList< String >迭代的例子
在这里插入图片描述
在这里插入图片描述
突变破坏了迭代器
在这里插入图片描述
其实很好理解,删掉第一个后,第二个换到了第一个的位置,但是迭代指向了第二个,其实是之前的第三个,所以最后有一个没有被删掉。所以在迭代的过程中进行这种增删操作是很容易出问题的。

七、有用的不可变类型

基本数据类型和其包装类都是不可变的。对于List、Set、Map都是可变数据类型。不过Collections具有获取这些可变集合的不可修改视图的方法:
Collections.unmodifiableList Collections.unmodifiableSet Collections.unmodifiableMap
使用举例:
在这里插入图片描述
在这里插入图片描述

八、空引用

初始数据类型不能赋值为null,注意在String类型中,null不等同与空字符串。
另外,非空的collection可以包含null值:
在这里插入图片描述
在这里插入图片描述
粗心地使用null会导致各种各样的错误, 接受null值不是好的策略。null的含义含糊不清。Map.get(key)返回null可能是key对应的值就是null,或者map中没有此key对应的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值