3.1数据类型与类型检查

  • 静态/动态类型检查
  • 可变/不变的数据类型
  • 可变数据类型的危险性
  • 不变数据类型的优越性
  • 用Snapshot图理解数据类型
  • 用集合类表达复杂数据类型
  • 理解空指针的危害并避免它

数据类型

  • 基本数据类型:小写字母,只有值,没有ID(与其他值无法区分),不可变,在栈中分配内存,代价低;
  • 对象数据类型:Classes,interfaces ,arrays,enums,annotations.既有ID也有值,一些可变,一些不可变;在堆中分配内存,代价昂贵;

对于对象数据类型都有root,是Object。对象类型形成层次结构;
基本数据类型可封装形成对象类型(不可变的):Boolean,Integer,Short,Long,Character,Float,Double;通常是在定义集合类型的时候使用他们,一般情况下,尽量避免使用,一般可以互相自动转换;

重载:同样的操作名可用于不同的数据类型;

静态 vs. 动态数据类型检查

java作为一种静态类型语言,在编译阶段进行类型检查;
python作为一种动态类型语言,在运行阶段进行类型检查;
静态类型检查>>动态>>无检查

静态类型检查:可在编译阶段发现错误,避免将错误代入到运行阶段,可提高程序正确性/健壮性;
静态检查的内容:语法错误;类名/函数名错误;参数数目错误;参数类型错误;返回值类型错误;

动态检查:

  • 非法的参数值;
  • 非法的返回值;
  • 越界;(例如:一个字符串中负数或太大的索引)
  • 空指针;
    趋向于对由于具体“值”引起的错误的检查;(例如:除0错误)

在例如Java的编程语言中,基本数据类型在某些情况不会表现的像真实的数字;结果使得有些错误静态/动态检查都无法检查到:

  • 整数除法:5/2不会返回一个分数,而是会返回一个整数;
  • 整数越界:例如int big = 200000*200000,会溢出返回一个错误的值;
  • 浮点数中的特殊的值:POSITIVE_INFINITY,NEGATIVE_INFINITY,例如:double a = 7/0;

可变量和不可变量

改变一个变量:将该变量指向另一个值的存储空间;
改变一个变量的值:将该变量当前指向的值的存储空间中写入一个新的值;
不变性:重要设计原则;
不变数据类型:一旦被创建,其值不能改变;
如果引用类型,也可以是不变的:一旦确定其指向的对象,不能被改变;
如果编译器无法确定final变量不会改变,就提示错误;
final类无法派生子类;
final变量无法改变值/引用;
final方法无法被子类重写;

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

String是不可变类型;
StringBuilder是可变类型;

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

不可变类型更“安全”,在其他质量指标上表现更好;

如何修改代码:

  • 通过防御式拷贝,给客户端返回一个全新的Date对象;例如return new Date (groundhogAnswer.getTime()),然而大部分时候该拷贝不会被客户端修改,可能造成大量的内存浪费;
  • 如果使用不可变类型,则节省频繁复制的代价;
  • 安全地使用可变类型:局部变量,不会涉及共享,只有一个引用;
  • 如果有多个引用(别名),使用可变类型就非常不安全;

Snapshot diagram作为一个code-level,run-time,moment view

用于描述程序运行时的内部状态;
3.1数据类型与类型检查
3.1数据类型与类型检查
3.1数据类型与类型检查
我们也可将一个可变的指针指向一个不可变的变量;3.1数据类型与类型检查
3.1数据类型与类型检查

复杂数据类型:Arrays and Collections

从Array到Arrays.asList(new String[] {"a","b","c"})
我们不能建立一个基本数据类型的集合;

List ,Set,Map都是接口;
List:ArrayList 和LinkedList;
Set: HashSet;
Map: HashMap;

Iterator 迭代器是可变类型;

3.1数据类型与类型检查

有用的不可变类型

基本数据类型及其封装对象类型都是不可变的;

Date是可变的;

可以对可变数据类型使用不可变的包装器,这种包装器得到的结果是不可变的:只能看;

  • 例如:Collections.unmodifiableList(),这样包装一个List,使得它的set(),add(),remove()等可变方法失效;
    但是,这种“不可变”是在运行阶段获得的,编译阶段无法据此进行静态检查;

3.1数据类型与类型检查

  • 浅拷贝:对于基本数据类型来说,拷贝一份互不影响;而对于数组和对象来说,只会拷贝数组或者对象的引用,对新旧数组进行修改,两个数组都会发生变化。
  • 深拷贝:指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。

空指针

空指针可能会造成危害