跳到内容

第 1 卷 / 第 2 章 / 第 2 课

2.2 基本类型的范围与边界 ​

前置知识:变量、赋值与作用域

预计时间:30 分钟

完成标志:能为整数、浮点、UTF-16 代码单元和真假值选择类型

四种整数类型 ​

类型位数最小值最大值常见用途
byte8-128127原始字节数据、紧凑数组、协议字段
short16-32,76832,767较少使用的窄整数数据
int32-2³¹2³¹ - 1默认整数选择、索引、计数
long64-2⁶³2⁶³ - 1超出 int 范围的整数

Java 规范固定这些数值范围,不随 CPU 位数变化。变量在对象、数组、栈帧或寄存器中的具体存储布局属于 JVM 实现与运行时优化问题,不能仅凭表中位数推导整个对象占用。

java
public class IntegerTypes {
    public static void main(String[] args) {
        byte small = 100;
        short port = 30_000;
        int population = 1_000_000;
        long distance = 3_000_000_000L;

        System.out.println(Byte.MIN_VALUE + ".." + Byte.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE + ".." + Integer.MAX_VALUE);
        System.out.println(distance);
    }
}

超过 int 范围的十进制整数字面量需要 L 后缀。优先大写 L,避免小写 l 与数字 1 混淆。

整数溢出会回绕 ​

java
int max = Integer.MAX_VALUE;
System.out.println(max);
System.out.println(max + 1);

结果:

text
2147483647
-2147483648

Java 整数加减乘的普通运算按固定宽度保留低位,结果表现为二进制补码回绕;它不会自动升级成 long,也不会因溢出自动抛异常。需要检测时使用:

java
int checked = Math.addExact(Integer.MAX_VALUE, 1);

这会抛出 ArithmeticException。换成 long 只能扩大范围,不能消除溢出可能;仍要根据业务边界选择校验策略。

float 与 double ​

类型位数大约十进制有效数字默认字面量
float326–7 位需要 F 后缀
double6415–16 位小数字面量默认类型
java
float ratio = 0.5F;
double temperature = 21.5;

二进制浮点数只能精确表示一部分十进制小数:

java
double sum = 0.1 + 0.2;
System.out.println(sum);
System.out.println(sum == 0.3);

典型输出:

text
0.30000000000000004
false

比较测量值时常使用与问题尺度匹配的容差,而不是固定套用某个“万能 epsilon”。需要精确遵守十进制金额和舍入规则时,通常使用 BigDecimal 或经明确设计的最小货币单位整数:

java
import java.math.BigDecimal;

BigDecimal price = new BigDecimal("0.10");
BigDecimal tax = new BigDecimal("0.20");
System.out.println(price.add(tax)); // 0.30

用字符串构造能按写出的十进制值建立对象;new BigDecimal(0.1) 会把二进制 double 的近似值带进去。

浮点类型还包含正无穷、负无穷和 NaN。例如浮点数除以 0.0 通常得到无穷或 NaN,与整数除以零抛 ArithmeticException 不同。

char 是 UTF-16 代码单元 ​

java
char grade = 'A';
System.out.println((int) grade); // 65

char 的取值是 0 到 65,535,对应一个 UTF-16 代码单元。它不保证表示一个完整的 Unicode 字符:基本多文种平面之外的码点需要一对代理项,也就是两个 char。

java
String symbol = "😀";
System.out.println(symbol.length());             // 2 个 UTF-16 代码单元
System.out.println(symbol.codePointCount(0, symbol.length())); // 1 个码点

因此“一个 char 等于一个用户看到的字符”并不可靠。即使一个 Unicode 码点,也不一定等于一个用户感知的字素簇。处理自然语言文本时优先使用 String 和按码点、分段器等合适 API。

单引号表示 char 字面量,双引号表示 String:

java
char letter = 'A';
String word = "A";

boolean 的语言边界 ​

java
boolean ready = true;
boolean finished = false;

Java 语言只允许 true 与 false,不允许把整数当作布尔值:

java
// boolean ready = 1; // 编译错误

Java 语言规范没有规定单个 boolean 变量必须占 1 bit 或 1 byte。字段、数组和 JVM 内部表示由不同层次的规范与实现决定,不能给它虚构一个固定大小。

整数除法与余数 ​

java
System.out.println(5 / 2);          // 2
System.out.println(5 % 2);          // 1
System.out.println(5 / 2.0);        // 2.5
System.out.println((double) 5 / 2); // 2.5

两个整数操作数触发整数除法,结果向零截断。至少一个操作数是浮点类型时,另一个会参与数值提升并执行浮点除法。

字段默认值与局部变量不同 ​

类字段和数组元素会被初始化为类型默认值:整数和 char 为零值,浮点为正零,boolean 为 false,引用为 null。方法局部变量必须先明确赋值才能读取。

java
public class Defaults {
    static int fieldCount; // 默认 0

    public static void main(String[] args) {
        int[] values = new int[2]; // 元素默认 0
        int localCount;

        System.out.println(fieldCount);
        System.out.println(values[0]);
        // System.out.println(localCount); // 编译错误
    }
}

Python 与 C++ 对照 ​

Python 的普通 int 支持任意精度,但仍受可用内存和实现限制;Python float 通常也是 IEEE 754 双精度,因此也有 0.1 + 0.2 的表示误差。Python 没有单独的 char 类型,长度为 1 的文本仍是字符串。

C++ 基本整数类型的最小范围由标准规定,实际宽度与实现和平台有关;sizeof(char) 固定为 1,但一个字节的位数由 CHAR_BIT 决定。C++ 有无符号整数,而 Java 的 byte、short、int、long 都有符号,char 则是无符号的 16 位整数类型。标准库另提供部分无符号运算 API。

专业速查 ​

场景建议
一般整数先用 int,根据经验证的范围升级
大整数long;超过其范围考虑 BigInteger
科学或测量计算通常 double,明确误差模型
精确十进制业务规则BigDecimal 或经过设计的定点整数
Unicode 文本String;明确代码单元、码点、字素簇层次
检测整数溢出Math.addExact 等 exact 方法或预先校验

离开这一页前 ​

如果只能记住边界,先记这五条:long 仍会溢出;double 不能精确表示所有十进制小数;char 是 UTF-16 代码单元;Java 没承诺单个 boolean 的固定存储大小;字段、数组元素和局部变量的初始化规则不同。

下一讲处理类型之间的移动。

→ 下一步:数值转换、提升与精度

规范入口:JLS §4.2:基本类型与取值、§4.12.5:变量的初始值。

Built with VitePress | Software Systems Atlas