软构复习4数据类型与类型检验

一、数据类型

数据类型:一些值的集合,以及在值上的操作

Java中的5种原始类型:int,boolean,double,long,char

对象类型:String,BigInteger

java中基本数据类型是小写,而对象数据类型是首字母大写

变量:用特定数据类型定义,并且存储满足类型约束的值

java中两种数据类型的比较:

除了object是祖先类以外,其他类都是继承了某一个类,继承形成了层次结构

子类从超类中继承可见的方法和成员,且可以重写超类方法

包裹类型:Boolean,Integer,Double,Short,Character,Float

通常在定义集合类型的时候使用它们,一般情况下尽量避免使用

包裹类型可以向下兼容它们的基本类型

重载(Overload):方法具有相同的名称,而参数列表(个数/类型)不相同,重载对返回类型是否相同不做要求

二、动态类型检查与静态类型检查:
java是静态类型语言:在编译阶段进行类型检查

动态类型语言:在运行阶段进行类型检查

一种语言提供的检查类型:静态,动态,无检查

静态>动态>无检查

Java验证类型是否始终匹配

静态类型检查在编译阶段发现错误,避免将错误带到运行阶段,提高了程序的健壮性和正确性

静态类型检查:

语法错误,函数名错误,参数类型错误,参数个数错误,返回值类型错误

动态类型检查:
非法的参数值:如整数x/y,只有在y实际为0时才会错误

非法的返回值:最后得到的返回值无法用声明类型表示,越界,空指针

静态类型往往是检查类型的,而动态类型检查检查特定值,一个错误由特定值触发,那编译阶段不会报错

int big = 200000
big = big * big ;
无报错,但是会出现错误的结果
double sum = 7 ;
double n = 0 ;
double average = sum / n ;
不报错,结果为无穷
int sum = 0;
int n = 0;
int average = sum/n;

动态类型错误

三、可变性与不变性:
赋值:用“=”,可以和变量声明结合在一起:double a=2.0

改变一个变量:将它指向另一个值的存储空间

改变一个变量的值:向它当前所指的值的存储空间中写入另一个值

程序不能没有变化,但是要尽量避免变化以避免副作用

不变数据类型:一旦被创建,值不能被改变 例如:String是,包裹类型是,List不是

在任何变量前面加final也可以使其成为不可变引用

final int a=5;(不能再被赋值了)

编译器会检查final修饰的变量值是否改变

尽量使用final变量作为方法的参数

注意:final类无法派生子类;final变量无法改变值/引用;final方法无法被子类重写

不变对象:一旦被创建,始终指向同一个值/引用
可变对象:拥有方法可以修改自己的值/引用
1.以String为例的不可变类型:

一旦创建一个String对象,它会始终指向同一个值,想获得一个新的字符串,需要创建一个新的String对象 

2.StringBuilder是可变类型,能够改变对象的值 

代码快照图
3.二者的区别
当只有一个引用指向该值的时候,没有区别,
但是多个引用指向一个值的时候,可变类型就可能出现问题
当另一个变量t指向与s相同的字符串对象,而另一个变量tb指向与sb相同的字符串构建器时,那么不可变对象和可变对象之间的差异就会变得更加明显:对String t和s的操作不会影响彼此所指的值,但是对sb和tb的操作改变的是同一个值,虽然sb没有被操作,但是对tb的操作导致sb指的值变成了abc
可变类型的优势:
可变类型最少化拷贝以提高效率,可以实现多模块的数据共享(但是也要知道全局变量的缺陷),可以获得更好的性能
不可变类型:对其频繁的修改会产生大量拷贝,需要垃圾回收机制
不可变类型:更加安全,在其他质量指标上表现得更好
例子1:传入可变类型参数

在main函数中,由于List是可变类型,所以计算sumAbsolute时将myData中的负数全部改为了绝对值,因此在计算sum时,结果为10,而不是预期的-10

可变类型的风险:首先容易出现问题,它改变了参数的值,超出了spec的范畴,且这种错误很难追踪和发现

其次,这种错误也很难被程序员理解,他们不仅要阅读main的代码,还要阅读sum和sumAbsolute的具体实现

例子2:返回可变类型参数:

有两个问题:
1.Date中的month取值0-11,如果到了12月,month=11,此时再加1,变成12,再set,由于setMonth的规约限制在0-11,所以会出现问题,其次,本例Date是可变类型,partyDate和groundhogAnswer指向同一个Date,如下快照图:

那么如果多次调用startofSpring,可能导致Month不断地增加,产生错误的值

可以使用java.time包中的LocalDateTime , Instant, 它们是不可变的

或者使用防御式拷贝:
return new
Date(groundhogAnswer .getTime());这种拷贝大部分时候不会被客户修改,会造成大量内存浪费

不可变类型则会节省频繁复制的代价

在局部变量上使用可变类型是安全的,因为不会共享,但是在由多个引用(别名)情况下,可变类型会变得非常不安全

防御式拷贝也会被攻击:

通过date内部的set方法改变end的年份

 四、代码快照图(run-time,moment,code level)

正在进行中的方法和本地变量在堆栈中,对象在堆中

对象值是用其类型标记的圆。–当我们想要显示更多细节时,我们在其中写字段名,箭头指向它们的值。对于更详细信息,字段可以包括它们声明的类型。

 不可变对象(其设计者希望总是表示相同的值)在快照图中用双边框表示,就像我们的图中的String字符串对象一样。

不可变的引用:双线箭头

引用是不可变的,其指向的值可以是可变的;可变的引用,也可以指向不可变的值

 对可变值的不可变引用如下:

静态检查到了final修饰的变量要改变,于是报错

还可以对不可变值进行可变引用:
 五、复杂数据类型:数组和集合

数组:定长,提前声明长度,会越界

 List:一个接口,变长,里面的成员是对象

迭代:对数组:用计数变量,从0到<array.length

对list:for each(但是不能增删元素)

Set:集合:每个对象只能在里面存有一个或不存有,方法:

 

Map:键,值成对存储

实现方式:List:LinkedList,ArrayList

Set:HashSet

Map:HashMap

Map<String, Double> treasures = new HashMap<>();
String x = "palm";
treasures.put("beach", 25.);
treasures.put("palm", 50.);
treasures.put("cove", 75.);
treasures.put("x", 100.);
treasures.put("palm", treasures.get("palm") + treasures.size());
treasures.remove("beach");
代码快照图:
迭代器:可变数据类型

next()返回集合中的下一个元素,它是可变方法

hasNext()判断迭代器是否到达集合结尾 

一个迭代器实例

 代码快照图

 list双线是因为用final修饰,由于ArrayList本身是可变的,所以final并不能阻止对list内部的改变

 迭代器思想:提供一个访问元素的通用中间件,以一种统一的格式访问各种集合类

 但可变性会暗中破坏迭代器:

删除所有以“6.”开头的课程,测试用例与预期如上

 

但是实际上:最后一个用例执行结果:

 代码快照图如下:

for each此时会显示越界

使用迭代器自己的remove方法,迭代器会自动调整索引

但是不会完全解决问题,如果多个迭代器指向同一个集合类,它们之间不会告知对方各自对集合类的修改

六、不可变类型:
基本类型和它们的包裹类型都是不可变的

集合实用程序类有一些方法来获取这些可变集合的不可修改的视图:

Collections.unmodifiableList
Collections.unmodifiableSet
Collections.unmodifiableMap
这种包装器得到的结果是不可变的:只能看
但是这种“不可变”是在运行阶段获得的,编译阶段 无法据此进行静态检查

 但是,对list的改变还是会导致对listCopy的改变:

 

不可修改的包装器有两个主要用途,如下:

在集合构建后使其不可变。在这种情况下,最好不维护对备份集合的引用。这绝对保证了不变性。允许某些客户端只读访问您的数据结构。您保留对备份集合的引用,但分发对包装器的引用。通过这种方式,客户端可以查看但不能修改,同时您保持完全访问。 

要从某些已知值创建不可变的集合,使用

List.of , Set.of , and Map.of .
List<String> a = List.of("lion", "tiger", "bear");
或者,使用List.copyOf(Java10)来创建不可修改的可变集合的浅层副本。

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值