Jakob Jenkov 发布于 2024-03-29
正如 Java 变量 一文中所解释的,Java 中的每个变量都有一个数据类型。数据类型分为两类:
- 基本数据类型(Primitive data types)
- 对象引用类型(Object references)
一个变量在内存中会占用一定空间,其所占内存大小取决于其数据类型。
基本数据类型的变量直接在分配给它的内存中存储该变量的值,例如一个数字或字符。
而对象引用类型的变量则与基本类型不同。这种变量也被称为“引用”。变量本身并不包含对象,而是包含一个指向对象的引用。这个引用指向内存中的某个位置,该位置存储了完整的对象。通过变量中存储的引用,你可以访问被引用对象的字段和方法。多个不同的变量可以引用同一个对象,这在基本数据类型中是不可能的。
基本数据类型
Java 语言包含以下基本数据类型:
| 数据类型 | 描述 |
|---|---|
boolean |
布尔值,取值为 true 或 false |
byte |
8 位有符号整数,取值范围 -128 到 127 |
short |
16 位有符号整数,取值范围 -32,768 到 32,767 |
char |
16 位 Unicode 字符 |
int |
32 位有符号整数,取值范围 -2,147,483,648 到 2,147,483,647 |
long |
64 位有符号整数,取值范围 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,808 |
float |
32 位浮点数 |
double |
64 位浮点数 |
这些被称为“基本数据类型”,意味着它们不是对象,也不是对对象的引用(类和对象将在本 Java 教程的后续文章中讲解)。
以下是声明一个基本类型变量的示例:
int myInt;
对象类型
基本类型也有对应的完整对象版本。这意味着你可以通过对象引用来使用它们,可以有多个引用指向同一个值,并且可以像调用其他 Java 对象一样调用它们的方法。下面列出了核心对象数据类型,其中包含了基本类型的对象版本,以及一些其他的 Java 核心对象类型:
| 数据类型 | 描述 |
|---|---|
Boolean |
布尔值,取值为 true 或 false |
Byte |
8 位有符号整数,取值范围 -128 到 127 |
Short |
16 位有符号整数,取值范围 -32,768 到 32,767 |
Character |
16 位 Unicode 字符 |
Integer |
32 位有符号整数,取值范围 -2,147,483,648 到 2,147,483,647 |
Long |
64 位有符号整数,取值范围 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,808 |
Float |
32 位浮点数 |
Double |
64 位浮点数 |
String |
N 字节的 Unicode 文本字符串(不可变) |
注意:对象类型的名称首字母大写,而对应的基本类型全部小写。此外还有一些缩写上的差异,例如 int 与 Integer、char 与 Character。
当然,Java API 中还有许多其他组件可用,但上述类型是 Java 的核心数据类型。
你也可以通过自定义类来创建更复杂的数据类型,相关内容将在后续文章中介绍。
以下是声明一个核心对象类型变量(即对象引用)的方式:
Integer myInteger;
当你声明一个对象引用变量时,该引用不会自动指向任何对象。你需要先创建(实例化)一个对象。如下所示:
Integer myInteger;
myInteger = new Integer(45);
此示例使 myInteger 变量引用一个内部包含值 45 的 Integer 对象。代码中的 new Integer(45) 部分负责创建该 Integer 对象。
你也可以在声明变量的同时创建对象,如下所示:
Integer myInteger = new Integer(45);
基本数据类型的对象版本是不可变的
基本数据类型的对象版本是不可变的(immutable),这意味着一旦对象被创建,其内部存储的值就无法更改。例如,Integer 对象中的值在创建后就不能再修改。
不过,引用该对象的变量可以被重新赋值,使其指向另一个对象。例如:
Integer myInteger = new Integer(45);
myInteger = new Integer(33);
如上所示,变量被重新赋值,现在指向另一个 Integer 对象。
自动装箱(Auto Boxing)
在 Java 5 之前,如果你需要从对象版本中获取其基本类型的值,必须显式调用方法。例如:
Integer myInteger = new Integer(45);
int myInt = myInteger.intValue();
从 Java 5 开始,引入了“自动装箱(auto boxing)”机制。这意味着 Java 可以在需要时自动将基本类型“装箱”为对应的对象类型,或者在需要时将对象类型“拆箱”为基本类型。例如,上面的代码现在可以简写为:
Integer myInteger = new Integer(45);
int myInt = myInteger; // 自动拆箱
同样地,以前手动创建对象版本的方式:
int myInt = 45;
Integer myInteger = new Integer(myInt);
现在可以简化为:
int myInt = 45;
Integer myInteger = myInt; // 自动装箱
Java 的自动装箱功能使得你可以在原本需要对象类型的地方使用基本类型,反之亦然。
但需要注意一个陷阱:对象类型的变量(即引用)可以为 null,表示它不指向任何对象。如果你尝试将 null 转换为基本类型值,将会抛出 NullPointerException(导致程序崩溃)。例如:
Integer myInteger = null;
int myInt = myInteger; // 运行时抛出 NullPointerException
这段代码虽然能成功编译,但在运行时会因 myInteger 指向 null 而抛出异常,因为无法从一个不存在的对象中“拆箱”出值。