【软件构造课程笔记】数据类型与类型检查

系列文章目录

第四章: Data Type and Type Checking



前言

第四章:Data Type and Type Checking

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

数据类型:数据类型定义为一组值以及在这些值上可以进行的操作的集合。
变量:变量是用特定的数据类型定义的,可以存储满足类型约束的值。

1. java中的数据类型

基本数据类型:例如int,long,boolean,double,char
对象数据类型:例如String,BigInteger
在java语言中,基本数据类型一般为首字母小写,而对象数据类型首字母一般为大写。
在这里插入图片描述
这张图较为详细的给出了基本数据类型与对象数据类型的异同。可以看到:

  1. 基本数据类型只有值没有ID,而对象数据类型既有值也有ID,使它可以与其他值进行区分。
  2. 基本数据类型都是不可变的数据类型,而对象数据类型则一些为可变,一些为不可变。
  3. 基本数据类型在栈中进行内存分配,对象数据类型在堆中分配内存。
  4. 基本数据类型的代价相对于对象数据类型要低。

2. 对象类型的形成层次结构

在这里插入图片描述
Object类是所有类的父类,提供了Java所有类的基础方法。
其他类可以由父类拓展而来,由上图中的extends语句指定。
子类可以继承父类的可见属性和方法,也可以通过重载的方式进行改变。

3. 封装基本数据类型

基本数据类型可以被包装为对象数据类型。
如: Boolean,Integer,Short,Long,Float,Double(开头首字母大写)
通常是在定义集合类型的时候使用它们,一般情况下,尽量避免使用(原因留在后面讲述)。
一般情况下两种类型可以进行自动的转换。

4. 操作

操作:操作是接受输入给出输出的一个函数(有时会改变给定参数的值)。

  1. 作为前,中,后缀操作如:a+b。
  2. 作为对象数据类型的方法:bigint1.add(bigint2)。
  3. 作为一个函数:Math.sin(theta),这里的Math不是对象数据类型,它是一个包含sin函数的类。

5. 重载

在这里插入图片描述

二、静态与动态类型检验

Java是一个静态类型语言,所有的变量类型在运行前就是已知的,因此编译器可以推断出所有表达式的类型:
例如:a和b都被声明为int类型,编译器可以推断出a+b也是int类型
所以eclipse环境可以在你还在编写代码时,为你找出关于类型不匹配的错误。大大提高了我们写代码的效率。
而在动态类型语言中(python),这种类型检验是在代码运行时进行的。
语言可以决定提供什么类型的检验(静态,动态,无)。
而不需要多说,静态类型检验>>动态类型检验>>无检验。

1. 静态类型检验

静态类型检查:可在编译阶段发现错误,避免将错误带入到运行阶段,可以提高程序的正确性与健壮性。
静态类型检查可以帮我们找到以下错误:

  1. 语法错误:不符合语法规范的语句,这种错误经常出现在我们编写代码的过程中。
  2. 类名/函数名错误:错误的拼写了类名或者函数名,导致编译器找不到。
  3. 参数数目错误:给出的参数数目与规约(后面会进行讲述)的不一致。
  4. 返回值类型错误:返回值的类型与我们函数声明的返回值不一致。

2. 动态类型检验

有关值的错误一般在动态类型检查中出现,例如:

  1. 非法的参数值:例如x/y当y为0时会出现除零错误,因为在编译阶段,编译器无法得知y的真正的值,所有只有在动态类型检验中才能找到错误。
  2. 非法的返回值:同样这里也是对于返回值的值的检查而不是对其类型的检查。
  3. 越界:例如:在数组中使用了负的或者太大的下标。
  4. 空指针

可以看出:静态类型检查是针对与“类型”的检查,不去考虑具体的值。
动态类型检查:针对值的检查。

三、可变类型与不可变类型

当我们用“=”去给一个变量进行赋值时,我们是改变了一个变量,还是改变了一个变量的值?这对于我们来说十分重要。

改变一个变量指的是:将该变量指向另一个值的存储空间。
改变一个变量的值指的是:将该变量当前指向的值的存储空间中写入一个新的值。
这两种不同的方式就引出了本章的重点:可变与不可变

1. 不可变性

不变性是一种重要的设计原则。

不可变数据类型:一但被创建,它的值与引用不能进行修改。
在Java中我们可以通过使用关键字final来将指定的变量的类型变为不可变类型
例如:final int n = 5;

我们需要注意:
1.final类无法派生出子类
2.final类无法改变值/引用
3.final方法无法被子类重写、

不变对象:一但被创建,始终指向同一个值/引用
可变对象:拥有方法可以修改自己的值/引用

2. String vs StringBuilder

我们在这里给出一个典型的例子:

  1. String是一个不可变的数据类型,所有一但String对象被创建,它只能一值拥有同一个值。在进行下述操作时,我们必须创建一个新的String对象并返回。
    在这里插入图片描述
  2. StringBuilder是一个可变的数据类型,它有方法对自己的值进行改变,所以我们不必创建一个新的对象并返回。
    在这里插入图片描述
  3. 我们也许会说这两种方式的结果是相同的,没有任何区别,只有一个引用指向该值时,确实是没有区别的。但是当存在多个引用时,差距就出现了。
    在这里插入图片描述
    我们可以看到,可变数据类型最少化拷贝的方式不会产生大量的临时拷贝,也不需要后续进行垃圾回收,提高了效率,也适合在多个模块之间共享数据。
    但是我们也要注意到:当使用可变的数据类型时,我们的值可能会出现意料之外的修改。这就有了一定的不安全信,相对于可变数据类型,不可变的数据类型有着更好的安全性。

3. 可变的隐含危险

在传递参数和返回返回值的时候使用可变的数据类型经常出现错误(如修改了参数的值,修改返回值的值),而且一旦出现错误,这种错误是非常难以发现和跟踪的。
例如:违反了规约,修改了参数的值。
在这里插入图片描述
例如:返回值为可变数据对象,并对返回值进行了修改。
在这里插入图片描述

4. 防御式拷贝

对于这种情况,我们可与选择使用不可变的数据类型,或者通过防御式拷贝,返回一个全新的对象。防御式拷贝虽然会造成大量的内存浪费,但是它是安全的。
防御式拷贝:
在这里插入图片描述

我们也要时刻注意安全地使用可变数据类型
安全地使用可变数据类型:局部变量,不会涉及到共享,只有一个引用。
如果有多个引用时,可变类型就非常不安全了。

四、snapshot diagram

在这里插入图片描述
在之前的章节中已经学习过了有关snapshot diagrams的知识。
snapshot diagrams用于描述程序运行时的内部状态,便于我们理解,便于刻画各类变量随时间的变化,也便于解释设计的思路,可以有效地帮助我们明白在代码的运行过程。
对于基本类型的值和对象类型的值,有下图的约定:
在这里插入图片描述
不可变对象:用双线椭圆
可变对象:用单线椭圆
在这里插入图片描述

不可变引用:用双线箭头
可变引用:用单线箭头
在这里插入图片描述

五、 复杂数据类型

1. Array

声明:int[] a = new int[100];

长度不可改变

2. List

声明:List list = new ArrayList();

List是一个interface
List 中的元素必须为对象数据结构
推荐使用List

3. Iterating

在这里插入图片描述

4. Set

Set体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素。加入Set的每个元素必须是唯一的,否则,Set是不会把它加进去的。要想加进Set,Object必须定义equals(),这样才能标明对象的唯一性。Set的接口和Collection的一摸一样。Set的接口不保证它会用哪种顺序来存储元素。
声明:Set set=new HashSet();

5. Map

Map 提供了一个更通用的元素存储方法。Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。从概念上而言,您可以将 List 看作是具有数值键的 Map。
声明: Map<String,Integer> m = new HashMap<String,Integer>();

因为本课程的内容不是Java语言的语法,所以在此不再加以赘述。
若想要更详细的教程,可以去http://www.51gjie.com/java/进行学习。

6. Iterator

Iterator 迭代器是一个对象,它遍历元素集合并逐一返回元素。

迭代器的两种方式:
在这里插入图片描述

六、 有用的不可变数据类型

基本类型及其封装对象类型都是不可变的。
而像List,Set,Map这样的常用集合类型都是可变的。
我们也可以用一些方法让这些数据类型变得不可变。
在这里插入图片描述
这种包装器得到的结果是不可变的:只能看
但是这种不可变是在运行阶段获得的,编译器无法根据此进行静态检查

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值