哈工大软件构造-数据类型和数据检查的课程总结


一、java数据类型

1. 基本数据类型(primitive types)

Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型
即byte(8位)、short、int、long、float、double、boolean、char
(数据类型转换时需要注意:不能对boolean类型进行类型转换)
特点:只有值,没有ID (与其他值无法区分),是不可变的,在栈中分配内存、代价低

2.对象数据类型 (object types)

如String、BigInteger等,开头字母需要大写
特点:既有ID也有值,有些可变/有些不可变,在堆中分配内存,代价昂贵

对象数据类型存在继承关系:如图,其中Object是所有对象类型的父类型
在这里插入图片描述

二、语言类型

1. 动态类型语言

动态类型语言是指在运行期间才去做数据类型检查的语言。也就是说,在用动态类型的语言编程时,永远不用给任何变量指定数据类型,该语言会在你第一次赋值给变量的时候,在内部将数据类型记录下来 。类型对于变量,属性,方法以及方法的返回类型都是可有可无的,在给变量赋值时才决定它的类型, 之后,还可以赋值不同类型的值,即使是基本类型,比如 C# 装箱(boxing)和拆箱(unboxing),可以把值类型转换成引用类型,引用类型转换成值类型。当需要时,很多类型之间都会发生自动转换,可以把不同的基本类型添加到同一数组(collections)中。

动态类型在解释语言中极为普遍,如 JavaScript、Perl、Python、Ruby 等等。

2.静态类型语言

静态类型语言与动态类型语言刚好相反,它的数据类型是在编译期间检查的。也就是说,在编写程序的时候就要声明所有变量的数据类型。C/C++是静态类型语言的典型带便,其它的静态类型语言还有C#、Java等

三、类型检查

1. 静态检查

可在编译阶段发现错误,避免了将错误带入到运行阶段,可提高程序正确性/健壮性
语法错误
例如多余的标点符号或者错误的关键词。即使在动态类型的语言例如Python中也会做这种检查:如果你有一个多余的缩进,在运行之前就能发现它。
错误的名字
例如Math.sine(2). (应该是 sin.)
参数个数不对
例如 Math.sin(30, 20).
参数类型不对
例如Math.sin(“30”).
错误的返回类型
例如一个声明返回int类型函数return “30”;

2.动态检查

非法变量名
例如整型变量x、y,表达式x/y 只有在运行后y为0才会报错,否则就是正确的。
无法表示的返回值
例如最后得到的返回值无法用声明的类型来表示。
越界访问
例如在一个字符串中使用一个负数索引。
使用一个null对象解引用

3.不报错但结果错误

整型除法
5/2的结果不为浮点数2.5,结果为一个整型变量
整型溢出
int big = 200000;
big = big * big;
结果为1345294336
浮点数中的特殊值 NaN (“Not a Number”), POSITIVE_INFINITY, and NEGATIVE_INFINITY
Math.sqrt(-9)的返回值为NaN

4.区分

静态类型语言在编译阶段进行类型检查
动态类型语言在运行阶段进行类型检查
当然,动态类型检查的语言也会进行静态检查(除了类型外的其他语法错误)

静态检查:关于“类型”的检查,不考虑值
动态检查:关于“值”的检查

四、可变类型

1.可变类型的优点

使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收)
可变类型因为最少化拷贝,可以提高效率
使用可变数据类型,可获得更好的性能
也适合于在多个模块之间共享数据

比如:
方案一:使用不可变类型String,每次修改s,都会产生一个新的字符串,原来的值被舍弃,产生大量的垃圾
在这里插入图片描述
方案二:使用可变类型StringBuilder,只产生一个对象,节约空间
在这里插入图片描述

2.可变类型的缺点

传递可变对象是一个潜在的错误源泉,一旦被无意中改变,则这种错误非常难于跟踪和发现

如:在该函数sumAbsolute中,调用了Math.abs()来计算元素的绝对值,但也与此同时修改了列表中元素的值。这可能不是我们在该函数中所期望的结果(超出了spec范畴),由此会产生一些难以被察觉的漏洞。
在这里插入图片描述
同理,如果有多个引用(别名),使用可变类型就非常不安全

3.安全使用方法

防御式拷贝
为了避免不可变类型数据在函数调用时被无意中改变,我们直接在ADT的getter方法中或其他返回可变类型的方法中采用防御式拷贝
通过防御式拷贝,给客户端返回一个全新的对象大部分时候该拷贝不会被客户端修改,可能造成大量的内存浪费
使用不可变类型
如果使用不可变类型,则节省了频繁复制的代价。因为,不可变类型不需要防御式拷贝
只有一个引用
局部变量,不会涉及共享

五、不可变类型

1.基本类型及其封装对象类型都是不可变的

2.不可变包装器

例如:List listCopy = Collections.unmodifiableList(list);
生成一个list的不可变对象listCopy,listcopy开起来与list相同,但是它的mutator是不可用的。如使用set() , add() , remove()会抛出异常
但是这种“不可变”是在运行阶段获得的,编译阶段无法据此进行静态检查

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值