Java 中的基本数据类型
1 基本数据类型-对象世界中的例外
在 Java 世界中万物皆对象,而基本数据对象看起来像是例外。
这是由于基本数据类型的使用频率很高,通过 new 的方式创建它们并保存值到堆内存中会消耗不必要的资源,所以直接创建变量并将值存到栈内存中的方式更加高效。由于 JVM 的存在,java 中的每种基本类型占用的内存大小是固定的,不随系统或机器环境而变化。
基本数据类型 | 占用空间大小 | 取值范围 | 包装类型 |
---|---|---|---|
byte | 8位 | -128~127 | Byte |
short | 16位 | 2^15 ~ 2^15 -1 | Short |
int | 32位 | -2^31 ~ 2^31 -1 | Integer |
long | 64位 | - 2^63 ~ 2^63 -1 | Long |
float | 32位 | IEEE754 | Float |
double | 64位 | IEEE754 | Double |
boolean | —— | Boolean | |
char | 16位 | Unicode 0 ~ 2^16 -1 | Character |
void | —— | —— | Void |
基本类型只有在作为成员变量时,具有默认的初始化值。
值得注意的是,一旦定义成员变量,这种初始化就一定会发生(非基本类型的变量,其初始引用为 null),且会发生在所有赋值操作之前,包括在定义时赋初始值的操作。
基本类型 | byte | short | int | long | float | double | boolean | char |
---|---|---|---|---|---|---|---|---|
默认值 | 0 | 0 | 0 | 0 | 0.0 | 0.0 | false | \u0000 (null) |
2 基本数据类型的对象化
基本类型有其对应的包装类型,完全可以在堆内存里表示基本类型的数据,所以基本类型仍然可以创建对象。
就连 void 也有对应的包装类型,而其包装类型 Void 的唯一作用就是占有 void 类型的 Class 对象的引用并使其不能被实例化。源码中给出了说明:
- The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void.
3 基本数据类型运算中值得注意的点
- 布尔(boolean)类型
布尔类型的大小虽然没有明确的规定,但可以认为它只占一位(1 bit),可以直接对 boolean 型变量执行与(&)、或(|)、异或(^)运算,但不能执行非(~)运算,这是为了避免与逻辑“非”(!)混淆。它们在布尔值上的计算效果和逻辑运算符相同,但计算不会有“短路”现象。
boolean b1 = true;
boolean b2 = false;
// %n 是忽略平台的换行符,但只有用 printf() 或 format() 才有效
System.out.printf("b1 & b2: " + (b1&b2) + "%n");
System.out.println("b1 | b2 " + (b1|b2));
System.out.format("b1 ^ b2: " + (b1^b2) + "%n");
// System.out.println("~b1: " + ~b1); // 错误: 一元运算符 '~' 的操作数类型boolean错误
System.out.printf("!b1: " + !b1);
- 整数类型(char/byte/short/int/long)
对小于 int 的基本数据类型(char/byte/short)执行任何算术或按位运算时,这些数据值会在执行运算之前被自动提升为 int 类型,计算结果的类型就为 int。必须使用强制转换才能使其回到较小的类型(由于重新分配回一个较小的类型,结果可能会丢失精度)。表达式中最大的数据类型决定表达式结果的数据类型。看下例。
byte b1 = 15, b2 = 16;
byte b = b1 + b2; // 错误: 不兼容的类型: 从int转换到byte可能会有损失
byte b = (byte)(b1 + b2);
long l = 31;
int i = 16;
int sum = l + i; // 错误: 不兼容的类型: 从long转换到int可能会有损失
long sum = l + i;
当 int 型整数运算结果超出 int 型的范围,就会发生溢出,而编译器也不会报错或警告,但会得到意外的结果。
int big = Integer.MAX_VALUE;
System.out.println(big); // 2147483647
System.out.println(Integer.toBinaryString(big)); // 1111111111111111111111111111111
int bigger = big * 4;
System.out.println(bigger); // -4
System.out.println(Integer.toBinaryString(bigger)); // 11111111111111111111111111111100
- 算术运算(+、-、*、/、%)与赋值运算(=、+=、-+、*=、/=、%=)中的坑
整数字面值默认为 int 类型,浮点数字面值默认为 double 类型。所以在有字面值参与的算术运算或直接赋值(=)时,需要注意类型转换的问题。请看以下示列:
short i = 20;
i = i + 2; // 错误:不兼容的类型: 从int转换到short可能会有损失
float f = 3.4; // 不兼容的类型: 从double转换到float可能会有损失
复合型的赋值运算符(+=、-+、*=、/=、%=)在赋值过程中会自动进行强制转换的操作,但不会检查结果是否溢出(即超出相应数据类型的取值范围)。请看以下示例:
byte b = 20;
b += 1; // 自动类型转换
System.out.println(b); // 21
b += 127; // 结果溢出
System.out.println(b); // -108