数据数据类型及定义,检测方式

Mutable, Immutable

snapshot图解析数据类型

1 Data type in programming languages 数据类型

A type is a set of values, along with operations that can be performed on those values. 数据类型 = 一组值 + 可执行操作

  • primitive types 基本数据类型:int, long, boolean, double, char
  • object types 对象数据类型:String, BigInteger
  • Java 约定:基本数据类型是小写字母开头,对象数据类型是大写字母开头
PrimitiveObject

对象类型层次结构:root is Object, all non-primitives are objects 继承关系

2 Static vs. dynamic data type checking

1
2
3
// 类型转换向下兼容
double a = 2; // a = 2.0(Implicit)
int a = 18.7; // ERROR

Java 是静态类型语言

变量的类型在编译时(在程序运行之前)已知,因此编译器也可以推断出所有表达式的类型(编译阶段进行类型检查)。

动态类型语言像 Python,这种检测将推迟到程序运行阶段。

Static Checking and Dynamic Checking

  • 静态类型检查:在程序运行前自动发现错误。往往是关于类型的检测,不考虑值。
  • 动态类型检查:必须运行程序,通过某种约束条件,对变量的值检测。往往是关于值的检测。
  • 无检查
  • 动态类型检查 >> 静态 >> 无检查,静态检测能检测就没必要用动态。

静态类型检查:可在编译阶段(编译器的工作)发现错误,避免了将错误带入到运行阶段,可提高程序正确性/健壮性。静态类型可以防止一大类错误,例如应用于错误类型的参数所导致的错误, "5" * "6" 字符串类型乘法这个错误在编程时被捕获。

静态类型检测能检测什么?

考虑编程过程会报哪些错误

  • Syntax errors 语法错误
  • Wrong names 类名/函数名错误
  • Wrong number of arguments 参数数目错误
  • Wrong argument types 参数类型错误:例如Type mismatch: cannot convert from int to boolean
  • Wrong return types 返回值类型错误
  • final变量,不被编译器相信只赋值了一次

动态类型检测能检测什么?

  • Illegal argument values 非法的参数值:例如divide-by-zero
  • Unrepresentable return values 非法的返回值,即特定的返回值不能用类型表示
  • Out-of-range indexes 越界
  • Calling a method on a null object reference. 空指针

3 Mutability and Immutability

这是一个对”类“的概念,基本数据类型无效

  • 改变一个变量:将该变量指向另一个值的存储空间
  • 改变一个变量的值:将该变量当前指向的值的存储空间中写入一个新的

Immutable types: 一旦被创建,其不能改变。

Java中基本数据类型一定是Immutable的。如果是引用类型,也可以是不变的:一旦确定其指向的对象,不能再被改变。

final保证了引用不变性,immutable是限制存储空间内容的不变性。

如果 Java 编译器不相信 final 变量在运行时只会被赋值一次,那么它就会产生一个编译器错误。 所以 final 提供了对不可变引用的静态检查。

尽可能多的用 final 来声明方法输入参数和作为局部变量

  • A final class declaration cannot be inherited. final class 不能被继承/无法派生
  • A final variable always contains the same value/reference but cannot be changed. final变量无法改变值/引用
  • A final method cannot be overridden by subclasses. final方法无法被子类重写,只能继承

String 类型是 immutable 类型,StringBuilder 是 mutable 类型

String StringBuilder
String StringBuilder
String s = "a"; StringBuilder sb = new StringBuilder("a");
s = s.contact("b"); sb.append("b");

当只有一个引用指向该值其实没什么区别,但是多个引用时就体现了区别。

MulitReferences

Immutable 类型,频繁修改会产生大量的临时拷贝(需要垃圾回收)。

Mutable 类型最少化拷贝以提高效率性能

Immutable 类型更“安全”。

避免由mutable类型带来的错误: 1. defensive copy:防御式拷贝,给客户端返回一个全新对象,可能造成大量的内存浪费 2. 使用不可变类型,则节省了频繁复制的代价

安全的使用可变类型:局部变量,不会涉及共享;只有一个引用

对同一个可变对象如果有多个引用(别名),就非常不安全

4 Snapshot diagram as a code-level, run-time, and moment view

SnapshotRule1
SnapshotRule2
SnapshotRule3
SnapshotRule4

An immutable/unreassignable reference to a mutable value:引用是不可变的,但指向的值却可以是可变的,例如:final StringBuilder sb

A mutable/reassignable reference to an immutable value:可变的引用,也可指向不可变的值,例如:String s

5 Complex data types: Arrays and Collections

List, Set, Map 都是接口

Iterator as a mutable type 迭代器:next(),hasNext()

Iterator

List和迭代器都属于mutable,上图中用迭代器来循环删除某个对象,后面的对象会向前对齐。

关于迭代和循环

6 Useful immutable types

  • 基本类型及其封装对象类型都是不可变的
  • Don't use mutable Date,
  • Collections types -- List, Set, Map are all mutable.
  • 包装器来获得 unmodifiable 不可变 collections:例如,List S = Collections.unmodifiableList(t);。这种不可变是在运行阶段获得的,编译阶段无法静态检查,并且只是增加了一个新的相同引用,对t修改也会报错。