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 基本数据类型运算中值得注意的点

  1. 布尔(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);
  1. 整数类型(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
  1. 算术运算(+、-、*、/、%)与赋值运算(=、+=、-+、*=、/=、%=)中的坑

整数字面值默认为 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
posted @ 2021-04-02 11:35  alterwl  阅读(84)  评论(0编辑  收藏  举报