java基础知识:
基本数据类型
基本数据类型是CPU可以直接进行运算的类型。Java定义了以下几种基本数据类型:
-
整数类型:byte,short,int,long
-
浮点数类型:float,double
-
字符类型:char
-
布尔类型:boolean
Java定义的这些基本数据类型有什么区别呢?要了解这些区别,我们就必须简单了解一下计算机内存的基本结构。
计算机内存的最小存储单元是字节(byte),一个字节就是一个8位二进制数,即8个bit。它的二进制表示范围从00000000
~11111111
,换算成十进制是0~255,换算成十六进制是00
~ff
。
内存单元从0开始编号,称为内存地址。每个内存单元可以看作一间房间,内存地址就是门牌号。
0 1 2 3 4 5 6 ...
┌───┬───┬───┬───┬───┬───┬───┐
│ │ │ │ │ │ │ │...
└───┴───┴───┴───┴───┴───┴───┘
一个字节是1byte,1024字节是1K,1024K是1M,1024M是1G,1024G是1T。一个拥有4T内存的计算机的字节数量就是:
4T = 4 x 1024G
= 4 x 1024 x 1024M
= 4 x 1024 x 1024 x 1024K
= 4 x 1024 x 1024 x 1024 x 1024
= 4398046511104
不同的数据类型占用的字节数不一样。我们看一下Java基本数据类型占用的字节数:
┌───┐
byte │ │
└───┘
┌───┬───┐
short │ │ │
└───┴───┘
┌───┬───┬───┬───┐
int │ │ │ │ │
└───┴───┴───┴───┘
┌───┬───┬───┬───┬───┬───┬───┬───┐
long │ │ │ │ │ │ │ │ │
└───┴───┴───┴───┴───┴───┴───┴───┘
┌───┬───┬───┬───┐
float │ │ │ │ │
└───┴───┴───┴───┘
┌───┬───┬───┬───┬───┬───┬───┬───┐
double │ │ │ │ │ │ │ │ │
└───┴───┴───┴───┴───┴───┴───┴───┘
┌───┬───┐
char │ │ │
└───┴───┘
byte
恰好就是一个字节,而long
和double
需要8个字节。
整型
对于整型类型,Java只定义了带符号的整型,因此,最高位的bit表示符号位(0表示正数,1表示负数)。各种整型能表示的最大范围如下:
- byte:-128 ~ 127
- short: -32768 ~ 32767
- int: -2147483648 ~ 2147483647
- long: -9223372036854775808 ~ 9223372036854775807
我们来看定义整型的例子:
// 定义整型
public class Main {
public static void main(String[] args) {
int i = 2147483647;
int i2 = -2147483648;
int i3 = 2_000_000_000; // 加下划线更容易识别
int i4 = 0xff0000; // 十六进制表示的16711680
int i5 = 0b1000000000; // 二进制表示的512
long l = 9000000000000000000L; // long型的结尾需要加L
}
}
基本数据类型/对象数据类型
静态/动态类型检查
(Java是静态类型检查,在编译阶段进行检查,Java不进行动态类型检测)
静态类型检查:语法、类名/函数名、参数数目、参数类型、返回值类型
动态类型检查:非法的参数值、非法的返回值、越界、空指针
注意List<String>和List<Object>是在静态类型检测中报错。
Mutable/Immutable
Java可进行自动垃圾回收。 Immutable好处:安全,但浪费空间。
*final特性: final 限定的是引用不变(如果mutable改变值不会报错),final类无法派生子类,final方法无法被子类重写。
使用Mutable可获得更好的性能,也适合多个模块间共享数据,但不够安全!
Date也是mutable类!避免使用!
可以使用java.time包中的其他immutable类型的类:LocalDateTime, Instant等
immutable拷贝时间 O(n2)
传参数尽量用immutable类型(保证参数不变性),如果传mutable参数可先进行defensive copying
必须通过类中的方法来改变类中的属性(防止信息泄露)
*Snapshot diagram
Immutable对象:用双线椭圆
不可变的引用(用final修饰的变量):用双线箭头
String s1 = new String("abc");
List<String> list = new ArrayList<String>();
list.add(s1);
s1 = s1.concat("d");
System.out.println(list.get(0));
String s2 = s1.concat("e");
list.set(0, s2);
System.out.println(list.get(0));
Array and Collections
Iterator
mutable类型,有两种方法:next()和hasNext(),next()方法是mutate的
需要注意,当用Iterator迭代List中元素,涉及到remove时,由于remove后List内元素索引会发生改变,会出现错误。
Collections
基本类型及其封装对象类型都是immutable的
List、Map、ArrayList等都是mutable的
可以利用Collections类提供的方法将mutable类包装成immutable
Collections.unmodifiableList Collections.unmodifiableSet Collections.unmodifiableMap
这种包装器得到的结果是不可变的,只能看,不能修改(其实就是disabled了一些mutate方法或者让其抛出异常)
这种”不可变“是在运行阶段获得的,编译阶段无法对此进行静态检查
虽然不能用包装后的对象对其进行修改,但依旧能用包装前的对象进行修改