Skip to content

数据类型与类型转换

这篇笔记聚焦 Java 里最基础、但也最容易“会用却没讲透”的一条主线:

  1. 数据类型到底怎么分类
  2. 基本数据类型和引用数据类型有什么区别
  3. 包装类型为什么会出现
  4. 自动装箱、拆箱和类型转换在解决什么问题
  5. ==equalsString 这些高频易混点到底该怎么理解

如果这条线没有打稳,后面学集合、泛型、并发和 JVM 时,很容易不断碰到边界理解不清的问题。


1. Java 的数据类型怎么分类

Java 的数据类型可以分成两大类:

  1. 基本数据类型
  2. 引用数据类型

这是最基础、也最重要的一层划分。

1.1 基本数据类型

基本数据类型 可以理解成 Java 语言内置的、用于直接表示简单数值或逻辑值的类型

它们不是对象,重点是:值本身就是数据。

Java 一共有 8 种基本数据类型:

  1. byte
  2. short
  3. int
  4. long
  5. float
  6. double
  7. char
  8. boolean

1.2 引用数据类型

引用数据类型 可以理解成 变量里保存的不是对象本体,而是指向对象的引用

常见的引用数据类型包括:

  1. 接口
  2. 数组
  3. 枚举
  4. 字符串

例如:

java
String name = "Java";
int[] nums = {1, 2, 3};

这里的 String 和数组都属于引用数据类型。


2. 8 种基本数据类型分别是什么

类型含义常见用途
byte8 位整数节省空间、字节流处理
short16 位整数较少单独使用
int32 位整数最常见的整数类型
long64 位整数大范围整数、时间戳等
float单精度浮点数较少作为精确计算首选
double双精度浮点数更常见的小数类型
char字符类型表示单个字符
boolean布尔类型表示真/假

这里要注意:

char 虽然看起来像字符,但底层本质上仍然是一个数值型编码单元。


3. 为什么 int 最常见,而不是 byteshort

很多人初学时会觉得:

byte 更省空间,是不是应该优先用它?

工程上通常不是这样。

更常见的原因是:

  1. int 是整数计算里最自然、最常用的默认类型
  2. CPU 和 JVM 对 int 的处理通常更直接
  3. byteshort 在表达式里经常还会被提升成 int

所以日常业务代码里,如果只是普通整数,默认优先考虑的通常是:int


4. 基本类型和引用类型最核心的区别是什么

可以抓住这几个点:

对比项基本数据类型引用数据类型
保存的是什么值本身对象引用
是否是对象
是否可为 null可以
默认值形态数值/布尔值null

更直白一点说:

  1. int a = 10;a 里就是 10
  2. String s = "abc";s 里更像是“指向这个字符串对象的位置”

5. 包装类型是什么,为什么会出现

Java 为每种基本数据类型都提供了对应的 包装类型

它可以理解成 把原本不是对象的基本类型,包装成一个对象类型

对应关系如下:

基本类型包装类型
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

包装类型出现的原因,核心是:Java 很多地方只能处理对象,不能直接处理基本类型。

比如:

  1. 泛型不能直接写 List<int>
  2. 集合里放的是对象
  3. 某些 API 需要对象语义

所以你会看到:

java
List<Integer> ids = new ArrayList<>();

而不会是:

java
List<int> ids = new ArrayList<>();

6. 自动装箱和拆箱是什么

6.1 自动装箱

自动装箱 可以理解成 把基本类型自动转换成对应的包装类型对象

例如:

java
Integer x = 10;

这背后本质上相当于:

java
Integer x = Integer.valueOf(10);

6.2 自动拆箱

自动拆箱 可以理解成 把包装类型对象自动转换回基本类型值

例如:

java
Integer x = 10;
int y = x;

这背后本质上相当于:

java
int y = x.intValue();

7. 自动装箱拆箱为什么容易出问题

因为它看起来像“自然语法”,但背后其实有对象和空值边界。

例如:

java
Integer x = null;
int y = x;

这段代码会抛出:NullPointerException

原因不是 int 有问题,而是:拆箱时需要从 Integer 对象里取出 int 值,但对象本身是 null。

所以包装类型参与运算时,一定要注意:

  1. 是否可能为 null
  2. 是否发生自动拆箱

8. 类型转换到底在说什么

类型转换 可以理解成 把一个类型的值,按规则转换成另一个类型来使用

在 Java 里,最常见分成两类:

  1. 自动类型提升
  2. 强制类型转换

8.1 自动类型提升

例如:

java
int a = 10;
long b = a;

这里是自动完成的,因为从较小范围整数到更大范围整数,通常不会丢失信息。

8.2 强制类型转换

例如:

java
double x = 10.8;
int y = (int) x;

这里必须显式写:

java
(int)

因为从 doubleint 可能会丢失信息。

这个过程不是“四舍五入”,而是:直接截断小数部分

所以结果会是:10


9. 表达式里的类型提升为什么容易让人困惑

因为有些看起来是小类型的运算,实际结果会先提升。

例如:

java
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);

这里 a + b 的结果在表达式计算时会先提升为 int
所以如果直接写:

java
byte c = a + b;

编译会报错。

这就是为什么很多人会觉得:

“明明两个 byte 相加,结果为什么不能直接放 byte?”

直接说:Java 的数值表达式有自己的类型提升规则。


10. ==equals 有什么区别

这是 Java 数据类型里最常见的混淆点之一。

10.1 对基本类型使用 ==

比较的是:值是否相等

例如:

java
int a = 10;
int b = 10;
System.out.println(a == b); // true

10.2 对引用类型使用 ==

比较的是:两个引用是否指向同一个对象

它不一定表示“内容相等”。

10.3 equals

equals 可以理解成 对象内容是否相等的一种逻辑比较方式

但前提是:这个类正确重写了 equals 方法。

如果想继续系统看:

  1. equals== 到底差在哪里
  2. 为什么重写 equals 时通常还要重写 hashCode
  3. 它们在 HashMapHashSet 中是怎么协同工作的

可以继续看:

例如:

java
String a = new String("abc");
String b = new String("abc");

System.out.println(a == b);      // false
System.out.println(a.equals(b)); // true

11. String 为什么总是被单独拿出来讲

因为 String 虽然是引用类型,但它在 Java 里非常特殊。

String 可以理解成 表示字符串内容的不可变对象

这里的 不可变,指的是:一旦创建,字符串对象本身的内容就不能再被修改。

它解决的是:

  1. 字符串共享更安全
  2. 哈希更稳定
  3. 在并发和常量池场景下更容易管理

12. 字符串常量池是什么

字符串常量池 可以理解成 JVM 为了复用字符串常量,专门维护的一块共享区域

例如:

java
String a = "hello";
String b = "hello";
System.out.println(a == b); // true

这里 ab 指向的通常是同一个常量池中的字符串对象。

但如果写成:

java
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false

那就是两个新对象。

所以 String 相关问题之所以容易混,是因为它同时涉及:

  1. 引用类型比较
  2. 对象内容比较
  3. 常量池复用

13. 小数为什么不建议直接用 float / double 做精确计算

因为 floatdouble 是浮点数类型,很多十进制小数在二进制里不能被精确表示。

这会导致:

  1. 精度误差
  2. 金额计算不准确

例如:

java
System.out.println(0.1 + 0.2);

结果通常不会是你直觉里的精确 0.3

所以在金额、计费这类精度敏感场景,更常见的做法是:使用 BigDecimal

BigDecimal 可以理解成 用于高精度数值计算的一种类,特别适合金额和精确小数场景


14. 常见误区

14.1 误区一:包装类型和基本类型没区别

不对。

它们在:

  1. 是否是对象
  2. 是否可为 null
  3. 是否参与装箱拆箱
  4. 是否能用于泛型

这些方面都有明显区别。

14.2 误区二:== 就是比较“内容一样不一样”

不准确。

对引用类型来说,== 更常是在比较:是不是同一个对象

14.3 误区三:double 足够表示所有小数

不对。

它适合一般浮点运算,但不适合要求严格精度的金额类场景。


15. 一句话总结

Java 的数据类型与类型转换这条主线,本质上是在解决:

值和对象到底如何表示、类型之间如何安全转换、哪些语言细节会在实际开发里引发空值、精度和比较语义问题。

基于 VitePress 构建的个人技术笔记。