首页 / Java 入门教程 / 类型转换

Java 入门教程

类型转换

本教程共 100 篇 · 第 13 篇 · 更新于 2026-08-05 · 约 5 分钟阅读

JavaJava 入门教程类型转换castingwidening强制转换parseInt

13. 类型转换

本节目标:理解不同类型之间怎么互相转换,分清「自动拓宽」和「强制转换」两种情形,并能避开溢出和精度丢失这两个坑。

为什么要转换

不同类型不能直接随便混。你把一个 int 赋给 double 没问题,反过来把 double 塞进 int 就可能丢东西。

Java 把类型转换分成两类:自动的(安全,编译器帮你做)和强制的(有风险,你自己负责)。

自动拓宽:小范围给大范围

当一个取值范围小的类型,赋值给一个取值范围更大的类型时,Java 自动帮你转,不需要写任何额外代码。

整数类型的「容量」从小到大是:

byte → short → int → long → float → double
```java

(字符 `char` 也可以直接赋给 `int`,因为它本质是个数字。)

```java
int a = 100;
long b = a;        // int → long,自动,安全
double c = b;      // long → double,自动,安全
char ch = 'A';
int code = ch;     // char → int,自动,code 得到 65

为什么安全?因为大碗装小碗的水,一滴不洒。数值信息不会丢。

Note

这里有个反直觉的点:float 虽然位数(32 位)比 long(64 位)少,但在类型链里 long 能自动转 float。因为 float 用科学记数法表示,能容纳很大的量级,只是可能损失些精度——Java 仍把它算作「拓宽」。

强制转换:大范围给小范围

反过来,把大范围塞进小范围,编译器不敢自作主张,必须你显式写强制转换,语法是在值前加 (目标类型)

double d = 9.99;
int n = (int) d;    // 强制转换,n 得到 9(小数部分直接丢掉)
```java

注意:`(int)` 不是四舍五入,是**直接截断**小数。9.999,不是 10

风险更大的是**溢出**。一个 `long` 里的值如果超过 `int` 上限,强转后只剩低位,结果完全错乱:

```java
long big = 3000000000L;   // 30 亿,超过 int 上限
int cut = (int) big;       // 溢出,cut 变成一个毫无意义的数
Warning

强制转换可能静悄悄地出错——编译不报错,运行结果却诡异。凡是看到 (int)(byte) 这类写法,都要在心里打个问号:值真的装得下吗?

反过来,int 也能强转回 char,只要数值落在字符编码范围内:

int code = 66;
char ch = (char) code;   // ch 得到 'B'
```bash

这和前面「`char` 自动变 `int`」正好相反:把编码值变回字符,得手动强转,因为 `int` 的范围比 `char` 大,属于窄化。这类字符与编码值的互相转换在处理文本、加密等场景里很常见。

## 运算时的类型提升

做混合运算时,Java 会先把「小个子」提升成「大个子」,再算:

```java
int a = 5;
double b = 2.0;
double result = a + b;   // a 被提升为 double,结果是 7.0

还有一个坑专门针对 byteshortchar:它们在参与运算前,统统先被提升成 int

byte x = 1;
byte y = 2;
// byte z = x + y;   // 报错:x+y 结果是 int,不能直接赋给 byte
byte z = (byte) (x + y);   // 必须强转回来
```bash

这是新手极易踩的坑。记住:两个 `byte` 相加,结果已经是 `int` 了。

## 数字字面量的默认类型

字面量也有默认类型:整数默认是 `int`,小数默认是 `double`。

```java
long n = 100;        // 100 是 int,自动拓宽成 long,OK
// float f = 3.14;   // 报错:3.14 是 double,不能自动变 float
float f = 3.14F;     // 加 F 显式声明为 float

前者没问题,是因为 int 字面量能自动拓宽进 long。后者要报错,是因为 double 不能自动变窄成 float,得加 F

字符串与数字互转

开发中经常要把用户在输入框里敲的数字(本质是字符串)转成真正的数字,或者反过来。

数字转字符串,最省事的是拼接空串,或用 String.valueOf

int age = 18;
String s1 = age + "";          // 拼接,得到 "18"
String s2 = String.valueOf(age);  // 更清楚,得到 "18"
```java

**字符串转数字**,用对应包装类的 `parseXxx` 方法:

```java
String s = "123";
int n = Integer.parseInt(s);       // 得到整数 123
double d = Double.parseDouble("3.14");  // 得到 3.14
Warning

字符串转数字时,内容必须是合法数字,否则运行时会抛异常(比如 Integer.parseInt("abc"))。真实项目里要处理这种意外,初学阶段先记住「转之前内容得是数字」即可。

如果要的不是基本类型 int,而是包装对象 Integer,用 valueOf

Integer boxed = Integer.valueOf("123");   // 字符串 → Integer 对象
Integer fromInt = Integer.valueOf(123);   // int → Integer 对象
Double dObj = Double.valueOf("3.14");     // 同理
```bash

> [!WARNING]
> 老教程里常见 `Integer` 的构造方法(`new Integer` 那种写法)。它从 Java 9 起已标记废弃,Java 25 LTS 中不要再用,一律改用 `Integer.valueOf()`。`valueOf` 不只是替代品,它还会复用 -128~127 的缓存对象,比每次 new 一个新对象更省内存。`Double`、`Boolean` 等其他包装类同理,构造方法一律换成 `valueOf`。

## 运算结果取「最大的那个类型」

混合运算时,结果的类型跟着操作数里「最大」的那个走。记住这条,能预判很多结果类型:

```java
int a = 10;
int b = 3;
double c = a / b;     // 这里 a/b 两个都是 int,先按 int 算得 3,再赋给 double 变 3.0

这段容易看走眼:ab 都是 int,所以 a / b整数除法,结果 3,赋给 double 后才变成 3.0。想要真正的 3.333,得让其中一个先变 double

double c = a / (double) b;   // 3.3333...
```bash

## 想四舍五入怎么办

`(int)` 是截断,不是四舍五入。要四舍五入用 `Math.round`:

```java
double d = 9.6;
long r = Math.round(d);   // 得到 10,最近的整数
int n = (int) Math.round(d);   // 想拿 int 再强转一下

Math.round 返回 long,所以常见写法是外面再包一层 (int)。它对负数同样按「四舍五入」规则处理(底层相当于加上 0.5 再截断取整)。

转换规则速查表

把前面散落的规则收拢成一张表,写代码拿不准时回看:

场景是否需要强转说明
intlong / double否(自动)小范围给大范围,安全
charint否(自动)字符转编码值
longint(int)可能溢出
doubleint(int)截断小数
byte/short 参与运算结果变 int(byte)/(short) 转回
字符串 → 数字Integer.parseInt内容须合法
Tip

拿不准要不要强转时,记住铁律:范围变大自动,范围变小手动。 手动就意味着你要为可能的溢出或丢精度负责。

小结

类型转换分自动拓宽和强制转换。小范围赋给大范围自动拓宽,安全;大范围强转给小范围需写 (类型),可能截断小数或溢出。

运算时 byte/short/char 先提升为 int;整数默认 int、小数默认 double

字符串与数字互转用 String.valueOfInteger.parseInt / Double.parseDouble;要包装对象则用 Integer.valueOf,包装类的构造方法自 Java 9 起已废弃,不要再用。