目录

  • 1. 引言与案例
  • 2. 什么是宽化转换
  • 3. 字面量的默认类型
  • 4. 算术运算中的提升
  • 5. 与装箱拆箱及重载决议
  • 6. 常见坑与实用建议
  • 7. 小测验
  • 8. 一句话记忆

1. 引言与案例

在这里插入图片描述

你在代码中写下:

long a = 999999999;   // 正常编译运行

为什么可行?因为:

  • 整数字面量默认类型是 int
  • 999999999 位于 int 的取值范围内(-2147483648 ~ 2147483647);
  • int 赋给 long 属于宽化转换(从较小范围到较大范围),是安全且无需强转的。

对比:如果字面量超出 int 范围,就必须显式标记为 long

long x = 2147483647;    // OK(仍在 int 范围内)
long y = 2147483648;    // 编译错误(默认按 int 解析,已溢出)
long z = 2147483648L;   // OK(L 表示 long 字面量)
long w = 3000000000;    // 编译错误
long v = 3000000000L;   // OK

2. 什么是宽化转换

  • 定义:把类型“向更宽的表示能力”转换的过程,通常是隐式且安全的,不需要强制类型转换。
  • 原始类型宽化链路
    • byte → short → int → long → float → double
    • char → int → long → float → double
  • 引用类型宽化:子类到父类,或实现类到接口,例如 ArrayList → List → Collection → Object

注意:虽然“整数 → 浮点”也被视为宽化(比如 int → floatlong → double),但它可能带来精度表示差异(浮点无法精确表示所有大整数)。

3. 字面量的默认类型

  • 整数字面量默认 int10xFF0b101007 等。
  • 浮点字面量默认 double1.03.141e3 等。
  • 需要 long:在整数字面量后加 L(推荐大写 L,避免和数字 1 混淆)。
  • 需要 float:在浮点字面量后加 F
  • 字符字面量如 'a' 的类型是 char

4. 算术运算中的提升

在算术运算中,较小整数类型(byteshortchar)会先被提升为 int,再参与计算,结果至少是 int

byte p = 1, q = 2;
var r = p + q;        // r 的类型是 int
// byte s = p + q;    // 编译错误:需要强制转换
byte s = (byte) (p + q);   // 显式强转后 OK

byte a1 = 1 + 2;      // OK:编译期常量折叠,且结果在 byte 范围内
byte a2 = 1 + p;      // 编译错误:含变量参与,结果提升为 int

混合运算遵循“向更宽类型靠拢”的规则:int → long → float → double。例如:

double d = 1L + 1.0F;   // 结果是 double

5. 与装箱拆箱及重载决议

它们是两套不同机制

  • 宽化转换:原始类型之间或引用类型继承层次间的“变宽”。不创建对象,编译期通常可判定。
  • 自动装箱/拆箱:原始类型与包装类型之间的自动转换(int ↔ Integerlong ↔ Long 等)。可能创建对象,拆箱时还可能触发 NullPointerException

在方法重载选择上,优先级通常为:原始类型宽化 > 自动装箱/拆箱 > 可变参数。并且,编译器不会做“装箱再宽化”的组合步(例如不存在 int → Integer → Long 的路径)。

示例:

void f(long x) {}
void f(Integer x) {}
void f(int... xs) {}

f(1); // 调用 f(long) —— 原始类型宽化优先

void g(Long x) {}
// g(1); // 编译错误:不能从 int 直接变为 Long(不会先装箱为 Integer 再“宽化”为 Long)

6. 常见坑与实用建议

  • 超出 int 范围的整数字面量必须加 L,否则以 int 解析会编译失败。

  • 整数除法会截断小数1/2 == 0。若要小数结果,用 1.01d1F 触发浮点运算:

    double r1 = 1 / 2;     // 0.0
    double r2 = 1.0 / 2;   // 0.5
    
  • 整数 → 浮点虽属“宽化”,但可能有精度差异(尤其是 long → floatlong → double)。对精度敏感的数量(如金额)请使用 BigDecimal

  • 拆箱可能 NPEInteger n = null; int x = n; // NPE

7. 小测验

  1. 下列哪行会编译失败?为什么?

    long a = 2147483647;
    long b = 2147483648;
    long c = 2147483648L;
    
  2. 下面的调用会选哪个重载?

    void h(long x) {}
    void h(Integer x) {}
    h(1);
    
  3. 下面的结果分别是什么?

    double x = 1 / 2;
    double y = 1.0 / 2;
    
  4. 说明下面为何编译错误,如何修正?

    byte b = 1;
    byte c = 2;
    byte d = b + c;
    

答案:

  1. long b = 2147483648; 失败。2147483648 默认按 int 解析且超范围;写成 2147483648L 即可。
  2. 选择 h(long),因原始类型宽化优先于装箱。
  3. x == 0.0(整数除法先算出 0 再宽化),y == 0.5
  4. b + c 提升为 int,赋给 byte 需强转:byte d = (byte) (b + c);

8. 一句话记忆

  • 整数字面量默认 int,浮点字面量默认 double;超出范围要用后缀(L/F)。
  • “小到大”的隐式转换叫宽化转换;运算时小整型先提升为 int
  • 重载决议:原始宽化 > 装箱/拆箱 > 可变参数;不做“装箱再宽化”。
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]