一、数据类型(java)
- 原始数据类型:int、long、boolean、double、char(小写开头)
- 对象数据类型:String、BigInteger(首字母大写)
- 两者具体区别
1.1 对象类型
Object对象是所有对象的祖先节点,除“对象”外的所有类都有一个父类,并使用扩展子句指定
If extends clause omitted, defaults to “Object”
一个类是其所有超类的一个实例
可以override 方法来改变他们的行为
1.2 包装基本类型
将基本类型包装为对象类型:
Boolean, Integer, Short, Long, Character, Float, Double
- 通常是在定义容器类型的时候使用它们(容器类型操作的元素要求是对象类型,所以需要对基本数据类型进行包装,转换为对象类型)
- 一般情况下,尽量避免使用(会降低性能)
- 一般可以自动转换
1.3 操作符
操作是接受输入并产生输出的函数
注意看String的操作
二、静态与动态数据检查
类型转换:
Java是一种静态类型的语言,所有变量的类型在编译时已知,因此编译器可以推导表达式类型,在编译阶段进行类型检查。
在像Python这样的动态类型语言中,这种检查会延迟到运行时(在程序运行时)。
- 静态检查:在程序运行之前就会自动发现这个错误。可以提高程序正确性/健壮性
- 动态检查:在执行代码时会自动发现错误。
- 没有检查:该语言根本不能帮助你找到错误。你必须自己注意,否则就会得到错误的答案。
- 静态检查 >> 动态动态 >> 无检查
- 动态类型检查的语言也会进行静态检查(除了类型外的其他语法错误)
动/静态检查的区别:- 静态检查:关于“类型”的检查,不考虑值
- 动态检查:关于“值”的检查
常见错误:
三、可变性和不可变性
-
可变性
赋值: Use “=” to give variables a value,赋值可以与变量声明组合在一起。
改变一个变量、改变一个变量的值,二者有何区别?- 改变一个变量:将该变量指向另一个存储空间。
- 改变一个变量的值:将该变量当前指向的存储空间中写入一个新的值
-
不可变性
- 不变性是一个主要的设计原则。
- 不变数据类型:一旦被创建,其值不能改变
- 如果是引用类型,也可以是不变的:一旦确定其指向的对象,不能再被改变指向其他对象
要使引用不可变,请使用关键字final声明它 - 编译器进行静态类型检查时,如判断final变量首次赋值后发生了改变,会提示错误。
- 尽量使用final变量作为方法的输入参数、作为局部变量
- final类无法派生子类
- final变量无法改变值/引用
- final方法无法被子类重写
-
不可变对象与可变对象
-
不变对象:一旦被创建,始终指向同一个值/引用(如String)要在字符串的末尾添加一些内容,你必须创建一个新的字符串对象
-
可变对象:拥有方法可以修改自己的值/引用(如StringBuilder)它有删除字符串的部分、插入或替换字符等方法。这个类有更改对象的值的方法,而不仅仅是返回新的值
当只有一个引用指向该对象,二者没有区别,有多个引用的时候,差异就出现了:
注:- 使用不可变类型,对其频繁修改会产生大量的临时拷贝(需要垃圾回收)
- 可变类型因为最少化拷贝,可以提高效率
- 它使用一个简单但聪明的内部数据结构,在最后使用toString()调用时完全避免进行任何复制。
- 使用可变数据类型,可获得更好的性能,也适合于在多个模块之间共享数据
那为什么还要用不可变类型?
- 不可变类型更“安全”,在其他质量指标上表现更好
- 可变性使得难以理解程序正在做什么,更难满足方法的规约。
- 不可变类型不需要防御式拷贝
- 大部分时候该拷贝不会被客户端修改,可能造成大量的内存浪费如,果使用不可变类型,则节省了频繁复制的代价
四、快照作为代码级、运行时和时刻视图的视图
- 快照用于描述程序运行时的内部状态
- 便于程序员之间的交流
- 便于刻画各类变量随时间变化
- 便于解释设计思路
注意不可变对象要用双线椭圆,不可变引用用双线箭头
五、复杂的数据类型:数组和集合
5.1 数组
- 定长数组(Array) 不可改变长度:int[] a = new int[length];
对其的操作:- 索引 a[index]
- 赋值 a[index] = val
- 取其长度 a.length
- 变长数组(List): List<Integer> list = new ArrayList<Integer>();
操作:- indexing: list.get(2)
- assignment: list.set(2, 0)
- length: list.size()
- 对数组使用迭代操作:
5.2 集合
集合是包含零个或多个唯一对象的无序集合,个对象不能在一个集合中多次出现。要么进去,要么出来
操作:
– s1.contains(e) test if the set contains an element
– s1.containsAll(s2) test whether s1 ⊇ s2
– s1.removeAll(s2) remove s2 from s1
5.3 字典 (key-value)
操作
– map.put(key, val) add the mapping key → val
– map.get(key) get the value for a key
– map.containsKey(key) test whether the map has a key
– map.remove(key) delete a mapping
5.4 声明
它们定义了这些各自类型的工作方式,但它们不提供实现代码
他们的迭代过程:
迭代器是一个对象,它遍历一组元素并逐个返回元素
for(…:…)形式的遍历,调用的是被遍历对象所实现的迭代器
迭代器两种方法:
- next()返回集合中的下一个元素;
- hasNext()测试迭代器是否已到达集合的结束
六、总结
可变性对于性能和方便性很有用,但它也会导致使用对象的代码在全局级别上表现良好的风险,这使得我们对其正确性所做的推理和测试复杂化了,关键的设计原则是不变性:尽可能多地使用不可变对象和不可变引用。学会了通过快照图可以迅速知道可变性、不可变性对象和引用之间的关系和区别。