静态类型检查和动态类型检查
Java是一种静态类型语言。所有变量的类型在编译时(在程序运行之前)都是已知的,因此编译器也可以推导出所有表达式的类型。如果a和b声明为int
,那么编译器得出结论,a+b
也是int
。
相比较之下,在像Python这样的动态类型语言中,这种检查会被推迟到run-time。
静态检查一个bug比动态检查好,而动态检查它比根本不没检查它好。
静态检查的好处就是可在编译阶段发现错误,避免了将错误带入到运行阶段,可提高程序正确性和鲁棒性。
静态类型检查其中的检查大体包含以下几种类型:
不用说,语法错误、名称错误这类肯定很容易理解。参数数目与类型这类的有关传参类型比较的都是静态检查,同理返回值类型也是。‘
动态类型检查其中的检查大体包含以下几种类型:
可见这些类型的错误一般都涉及到实际的数据,这里非法参数值和非法返回值指的不是类型错误,而是value错误,一般是除0之类的错误。
越界就是访问超过了空间限制,例如一个数组的索引不可以是负数,也不能用超过界限的索引去访问字符串等等。
空指针访问在CSAPP里有过了解。
Useful immutable types
基本类型及其封装对象类型都是不可变的。例如 BigInteger和BigDecimal这种。
Java的Collection类型的常规实现有 List, Set, Map 这些都是mutable,ArrayList, HashMap等。
Collection具有获取这些可变集合的immutable视图的方法:
称为Immutable Wrappers around Mutable Data Types
这种包装器得到的结果是不可变的:我们只能看里边包含了哪些元素,不能改变。
Collections.unmodifiableList( )获取一个List,并用一个看起来像一个List的对象来包装它,但它的变值器mutators已被禁用——设置()、添加()、删除()等等,使用他们会抛出异常。因此,我们可以使用变值器mutators构建一个列表,然后将其密封在一个不可修改的包装器中(并放弃对原始可变列表的引用,并得到一个不可变列表)。但是这种“不可变”是在运行阶段获得的,编译阶段无法据此进行静态检查。也就是就算你改了,编译器的静态检查也不会报错。只有运行时才会报错。
不可修改的包装器通过拦截所有将修改collection的操作并抛出不受支持的操作异常,从而剥夺了修改collection的能力。
- 使collection构建之后不可变。在这种情况下,最好不保持对原对象的引用。
- 允许某些客户端只读访问数据结构。自己留着可变的引用,给别人不可变的包装。
如果要从某些已知值创建不可变集合,可以使用List.of、Set.of和Map.of。
List<String> a = List.of("lion", "tiger", "bear");