2.2 基本类型的范围与边界
前置知识:变量、赋值与作用域
预计时间:30 分钟
完成标志:能为整数、浮点、UTF-16 代码单元和真假值选择类型
四种整数类型
| 类型 | 位数 | 最小值 | 最大值 | 常见用途 |
|---|---|---|---|---|
byte | 8 | -128 | 127 | 原始字节数据、紧凑数组、协议字段 |
short | 16 | -32,768 | 32,767 | 较少使用的窄整数数据 |
int | 32 | -2³¹ | 2³¹ - 1 | 默认整数选择、索引、计数 |
long | 64 | -2⁶³ | 2⁶³ - 1 | 超出 int 范围的整数 |
Java 规范固定这些数值范围,不随 CPU 位数变化。变量在对象、数组、栈帧或寄存器中的具体存储布局属于 JVM 实现与运行时优化问题,不能仅凭表中位数推导整个对象占用。
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 混淆。
整数溢出会回绕
int max = Integer.MAX_VALUE;
System.out.println(max);
System.out.println(max + 1);结果:
2147483647
-2147483648Java 整数加减乘的普通运算按固定宽度保留低位,结果表现为二进制补码回绕;它不会自动升级成 long,也不会因溢出自动抛异常。需要检测时使用:
int checked = Math.addExact(Integer.MAX_VALUE, 1);这会抛出 ArithmeticException。换成 long 只能扩大范围,不能消除溢出可能;仍要根据业务边界选择校验策略。
float 与 double
| 类型 | 位数 | 大约十进制有效数字 | 默认字面量 |
|---|---|---|---|
float | 32 | 6–7 位 | 需要 F 后缀 |
double | 64 | 15–16 位 | 小数字面量默认类型 |
float ratio = 0.5F;
double temperature = 21.5;二进制浮点数只能精确表示一部分十进制小数:
double sum = 0.1 + 0.2;
System.out.println(sum);
System.out.println(sum == 0.3);典型输出:
0.30000000000000004
false比较测量值时常使用与问题尺度匹配的容差,而不是固定套用某个“万能 epsilon”。需要精确遵守十进制金额和舍入规则时,通常使用 BigDecimal 或经明确设计的最小货币单位整数:
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 代码单元
char grade = 'A';
System.out.println((int) grade); // 65char 的取值是 0 到 65,535,对应一个 UTF-16 代码单元。它不保证表示一个完整的 Unicode 字符:基本多文种平面之外的码点需要一对代理项,也就是两个 char。
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:
char letter = 'A';
String word = "A";boolean 的语言边界
boolean ready = true;
boolean finished = false;Java 语言只允许 true 与 false,不允许把整数当作布尔值:
// boolean ready = 1; // 编译错误Java 语言规范没有规定单个 boolean 变量必须占 1 bit 或 1 byte。字段、数组和 JVM 内部表示由不同层次的规范与实现决定,不能给它虚构一个固定大小。
整数除法与余数
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。方法局部变量必须先明确赋值才能读取。
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 的固定存储大小;字段、数组元素和局部变量的初始化规则不同。
下一讲处理类型之间的移动。