基本数据类型
- 整数型:
byte、short、int(默认)、long - 浮点型:
float、double(默认) - 字符型:
char - 布尔型:
boolean
每个数据类型所占的字节数
| 数据类型 | 关键字 | 内存占用 |
|---|---|---|
| 字节型 | byte | 1个字节 |
| 短整型 | short | 2个字节 |
| 整型 | int | 4个字节 |
| 长整型 | long | 8个字节 |
| 单精度浮点型 | float | 4个字节 |
| 双精度浮点型 | double | 8个字节 |
| 字符型 | char | 2个字节 |
| 布类型 | boolean | * |
boolean类型占的字节数
《Java虚拟机规范》一书中的描述:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替;而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8。
经过查阅资料发现,使用int的原因是,对于当下32位的处理器(CPU)来说,一次处理数据是32位(这里不是指的是32/64位系统,而是指CPU硬件层面),具有高效存取的特点。
从上面这句话得出两个结论:
- 单独使用是4个字节
- 在数组中是1个字节
注意事项
- 浮点型只是近似值不是精确值,比较时需要使用
BigDecimal - 数据范围与字节数不一定相关,
float是4字节、long是8字节,但是float范围比long更广 - 浮点型默认是
double类型,使用float类型需要在后面加上F;整型默认是int,使用long类型需要在后面加上L
编译器的两点优化
- 对于
byte、short、char三种类型,如果右侧赋值的数值没有超过左侧的范围,编译器会自动隐含地帮我们自动补上;如果超过了左侧的范围,直接报错 - 在给变量进行赋值的时候,如果右侧的表达式中全都是常量,没有任何变量,那么编译器javac会直接将若干个常量表达式计算得到结果。编译时赋值,不用等到运行时再去耗费cpu计算,这称为编译器的常量优化,但是一旦表达式中有其他变量参与(有符号引用),那么就不能进行这种优化了
包装类
- 为什么要用包装类?
基本数据类型虽然使用非常方便,但是没有对应的方法操作这些基本数据类型,可以使用包装类来操作这些数据。比如:compare、类型转换等
装箱与拆箱
- 装箱:基本数据类型->包装类型
- 拆箱:包装类型->基本数据类型
- 以Integer为例
//装箱
Integer(int value); //过时
static Integer valueOf();
Integer result = Integer.valueOf(x);
//拆箱
int intValue();
int x = result.intValue();
- 自动装箱与自动拆箱
//自动装箱
Integer result = 1; //相当于Integer result = new Integer(1);
//自动拆箱
result = reuslt + 2; //result + 2相当于result.intValue() + 2;
- 尽量不要把有自动装箱拆箱的代码写到循环中去 会降低效率
BigDecimal
- 作用:浮点型之间的等值判断,基本数据类型用
==来比较,包装类型不能用equals来比较。原因:精度丢失 - 使用
BigDecimal来定义浮点型数据的值,再进行浮点数的运算操作
包装类型和基本数据类型的区别
- 从类型来看:包装类型可以用于泛型,基本数据类型不可以。因为在编译过程中会进行
泛型擦除,最后只保留原始类型,而原始类型只能是Object类,包装类型都是Object类型,基本数据类型没有原始类型 - 从值来看:包装类型可以为null,基本数据类型不可以为null。包装类型可以用于POJO,基本数据类型不可以,因为数据库查询结果可能为null,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值
int intValue()),就会抛出NullPointerException的异常。 - 从比较环节看:基本数据类型用
==比较,包装类型需要使用equals,用==比较的是地址值。如果包装类型和基本数据类型进行==比较会自动拆箱 - 从效率来看:基本数据类型比包装类型更高效。基本类型在栈中直接存储的具体数值,而包装类型在栈中存储的是堆中的引用。很显然,相比较于基本类型而言,包装类型需要占用更多的内存空间。假如没有基本类型的话,对于数值这类经常使用到的数据来说,每次都要通过new一个包装类型就显得非常笨重。
- 从用途来看:局部变量一般使用基本数据类型;POJO的属性一般使用包装类型
包装类的缓存机制
- JVM中一个字节以下的整型数据会在JVM启动的时候加载进内存,除非用
new Integer()显式的创建对象,否则都是同一个对象。当Integer需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不是重新创建一个对象 - 以Integer为例,当使用自动装箱的方式去创建一个Integer实例时,当数值在[-128,127]之间,会使用缓存中的实例,IntegerCache静态成员内部类,其中一段静态代码是缓存[-128,127]之间的Integer实例。这个范围其实可以调整,通过调整虚拟机参数
-XX:AutoBoxCacheMax=<size>来设置缓存的最大值,因为在IntegerCache里面已经预设好了low为-128,但是high是没有显式写出来的,默认是127。 - 其他类型也有缓存机制,Byte,Short,Integer,Long为 -128 到 127,Character范围为 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行