数据类型
基本数据类型
JAVA中一共有八种基本数据类型:
byte、short、int、long、float、double、char、boolean
类型 | 类别 | 字节 | 取值范围 |
---|---|---|---|
byte | 整型 | 1byte | -27 ~ 27-1 |
short | 整型 | 2byte | -215 ~ 215-1 |
int | 整型 | 4byte | -231 ~ 231-1 |
long | 整型 | 8byte | -263 ~ 263-1 |
float | 浮点型 | 4byte | 3.402823e+38 ~ 1.401298e-45 |
double | 浮点型 | 8byte | 1.797693e+308~ 4.9000000e-324 |
char | 文本型 | 2byte | 0~216-1 |
boolean | 布尔型 | 1byte | true/false |
要点:
- 整数值默认为int类型
- 小数默认是double类型
- 浮点型的数据是不能完全精确的
- String不是基本数据类型
- 整数的最高位为符号位
Java虚拟机中所支持的与数据类型相关的字节码指令中,大部分都没有支持整数类型的byte、char、和short,甚至没有任何指令支持boolean类型。编译器会在编译期或运行期将byte和short类型的数据带符号扩展为相应的int类型数据,将boolean和char类型数据零位扩展为相应的int类型数据。与之类似的,在处理Boolean、byte、short、和char类型的数组时,也会转换为使用对应的int类型的字节码指令来处理。因此,大多数对于Boolean、byte、short、和char类型的数据操作,实际上都是使用相应的int类型做为运算类型的(《深入理解Java虚拟机》第二版P198)
自动类型转换
要点:
- 两种类型是彼此兼容的
- 转换后的目标类型占的空间范围一定要大于被转化的原类型
- 数据类型自动提升
- 如果操作数其中有一个是double类型,两个操作数都转换为double类型
- 否则,如果其中一个操作数是float类型,两个操作数都转换为loat类型
- 否则,如果其中一个操作数是long类型,两个操作数都转换为long类型
- 否则,两个操作数都转换为int类型
public static void main(String[] args) {
//编译时125,128都是int,编译的时候会检查是否超过byte的范围
byte a1 = 125;//没有的话,编译器会自动转为byte
byte a2 = 128;//超过了,编译期间就或报错
byte b1 = 1;
byte c1 = 1+1;//表达式中只有常量则会进行常量折叠,等效于byte c1 = 2;
byte c2 = b1+b1;//计算时转换为int,int赋值给byte报错
//编译时99999999999999是int,编译的时候会检查是否超过long的范围
long d1 = 99999999999999; //超过了,则会报错
//计算时,整数都默认为int,除非加了L后缀表示为long类型
long d2 = 1000*1000*1000*10;//结果为1410065408:错误,因为超过了int的范围,损失精度,再赋值给long类型时已经是错误的结果了
long d3 = 1000*1000*1000*10L;//结果为10000000000:正确,因为有个10L,将整个表达式提升为long类型
long d4 = 1000*1000*1000*10*1L;//结果为1410065408:错误,因为在类型提升之前,计算结果就已超过了int的范围,损失精度,再赋值给long类型时已经是错误的结果了
}
强制类型转换
显式的强制类型转换遵循以下格式:
TYPE a = (TYPE) B
显式的类型转换大概划分为三种情况:
-
高位整型、字符型向低位整型、字符型的强制类型转换
- 目标类型的长度小于源类型的长度,则在源类型低位直接截取目标类型的长度的数据
-
浮点型向整型的强制类型转换
- 若不超过long或int的最大值,就省略小数部分直接赋值
- 若超过long或int的最大值,那么强制类型转换的结果就是long或int对应的最大值
- 浮点型转换为byte/char/short时,需要先以int为跳板,即先转换为int。再按整型的强制类型转换规则,按目标类型长度截取低位数值
-
高位浮点型向低位浮点型的强制类型转换
- double数值在float允许范围之内,float将会直接获取符号位、阶数,并根据浮点数的舍入规则,将double类型52位的尾数舍入为float类型的23位尾数
- double数值超出float允许范围,这种情况往往是因为阶码部分超出表示范围,尾数只决定精度,阶码才决定范围。若出现这种情况,最后的结果将会输出Infinity或-Infinity,也即正无穷和负无穷。但这并不是数据上的无穷,只是因为浮点数存储机制带来的一种结果
隐式的强制类型转换(只能当两个类型可转时才能进行)
-
在赋值表达式中,如果赋值符左右两侧的操作数类型不同,则将赋值符号右操作数强制转换为赋值符号左操作数的类型,然后进行赋值
-
在函数调用时,如果return后面的表达式的类型与函数返回值类型不同,则在返回值时将return后的表达式的数值强制转换为函数返回值所定义的类型,再将返回值进行返回
包装类型
基本类型对应的包装类型:
基本数据类型 | 包装类型 |
---|---|
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
包装类型的应用:
- 集合类泛型只能是包装类
- 当需要成员变量不能有默认值时(例如PO)
- 方法参数允许定义空值时
自动装箱拆箱:
- 自动装箱即自动将基本数据类型转换成包装类型(java在编译Integer i = 1;的时候,被翻译成->Integer i = Integer.valueOf(1);)
- 拆箱就是自动将包装器类型转换为基本数据类型
- 自动装箱拆箱是编译时特性(如果编译时是Integer 需要拆箱,那么运行时传入的参数就必须是Integer )
Java 缓存策略:
Integer的缓存:
Java5为Integer的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用
- 默认适用于整数区间 -128 到 +127(这个整数区间可以通过启动应用的虚拟机参数修改:-XX:AutoBoxCacheMax)
- Integer缓存策略仅在自动装箱(autoboxing)的时候有用
- 使用构造器创建的Integer对象不能被缓存(构造器方法已被废除,不建议使用)
缓存策略对比较的影响:
- 无论如何,Integer与new Integer不会相等。不会经历拆箱过程
- 两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false
- 两个都是new出来的,都为false
- int和Integer(无论是否new的对象)比,都为true,因为会把Integer自动拆箱为int再去比
Integer的缓存上限可以通过Java虚拟机参数修改,Byte、Short、Long、Character的缓存则没法修改