跳到内容

前置知识:第2章——你认识了 8 种基本类型和它们的取值范围

本章分层

  • 必读:隐式转换规则、强制转换语法、数据丢失与溢出
  • 选读Integer.MAX_VALUE 溢出回绕、表达式自动类型提升
  • 进阶:自动装箱/拆箱的编译器行为(第7章会详细讲)

老陈的盒子排成一排

老陈师傅把几个大小不一的木盒子排开——最小的像火柴盒(byte),最大的像旅行箱(double)。

"有时候你需要把一种类型的值放到另一种类型的变量里。关键问题:方向很重要。"


自动转换(隐式):小→大

从小盒子换到大盒子,安全,自动发生:

java
int i = 100;
long l = i;      // int 自动变成 long——小盒子装进大盒子,安全
double d = i;    // int 自动变成 double——整数变小数,不丢精度

规则很简单——箭头方向上的转换自动发生,因为目标类型的范围更大:

byte → short → int → long → float → double

注意 float(4 字节)排在 long(8 字节)后面?是的——因为 float 虽然字节少,但能表示的最大值比 long 大得多(科学计数法)。


强制转换(显式):大→小

反过来就不行:

java
double pi = 3.14159;
int i = pi; // 编译错误:incompatible types

"能编过才怪。"你把一个可能装了 3.14 的大箱子,强行塞进只能装整数的小箱子——数字丢了小数部分。Java 不会替你做这个决定。你得明确说:我知道我会丢精度,我同意。

java
double pi = 3.14159;
int i = (int) pi; // (int) 是强制类型转换
System.out.println(i); // 输出:3(小数部分被截断,不是四舍五入!)

括号里写目标类型,这叫强制类型转换(cast)

完整演示:

java
// TypeConversion.java
public class TypeConversion {
    public static void main(String[] args) {
        // 隐式转换——自动
        int apples = 10;
        long total = apples;   // int → long
        double price = apples; // int → double

        // 显式转换——手动,有风险
        double weight = 85.7;
        int kg = (int) weight; // double → int,丢掉 0.7

        // 危险操作:数据溢出
        int big = 1000;
        byte small = (byte) big; // 1000 远超 byte 范围(-128~127)

        System.out.println("long: " + total);
        System.out.println("double: " + price);
        System.out.println("int (from double): " + kg);
        System.out.println("byte (from int): " + small);
    }
}

如何运行: javac TypeConversion.javajava TypeConversion预期输出:

long: 10
double: 10.0
int (from double): 85
byte (from int): -24

"看到了吧?(byte) big 输出 -24——这不是 Java 的 bug,而是溢出回绕。1000 的二进制超过了 byte 能表示的范围(-128~127),剩余部分从最左边被截掉,结果变成了 -24。"

所以——强制类型转换是你在跟编译器说:别管我,我知道我在干什么。 大多数时候你知道,但你也可能犯错。


表达式中的自动类型提升

当不同类型参与运算时,Java 会自动把"较小"的类型提升到"较大"的类型:

java
int i = 5;
double d = 2.0;
double result = i + d; // i 自动提升为 double,结果是 double

运算结果是最"大"的那个类型。


关于装箱(Boxing)的说明

你可能听说过"自动装箱"和"拆箱"——比如 Integerint 之间的自动转换:

java
Integer x = 100; // 自动装箱:int → Integer(包装类)
int y = x;       // 自动拆箱:Integer → int

本章不深入讲这个。 你只需要知道基本类型有对应的包装类(IntegerDoubleBoolean 等),在第7章面向对象时会详细解释。现在用基本类型(intdouble)就足够了。


Python 差异: Python 没有"类型转换"的说法——int(3.14) 得到 3,这不叫 cast,叫构造函数调用。Java 的类型转换发生在编译期,而 Python 的 int(3.14) 发生在运行时。Python 也不存在数据溢出,因为它的整数可以任意大。

C++ 差异: C++ 有四种不同的 cast 操作符(static_castdynamic_castconst_castreinterpret_cast)——Java 只有一种 (type) 括号语法。而且 C++ 对有符号整数的溢出是未定义行为(编译器可能做任何事),但 Java 严格规定了溢出回绕行为。


→ 下一步:动手练习

理论够了。拿起键盘,声明变量、测试类型转换、踩一遍常见陷阱——代码写熟了才算真正掌握。

动手练习 & 排障指南 →

Built with VitePress | Software Systems Atlas