跳到内容

前置知识:第2章——你已经知道变量是什么,能声明变量并赋值

本章分层

  • 必读:各基本类型的取值范围与用法、整数溢出、浮点精度陷阱
  • 选读:IEEE 754 浮点数表示、类型默认值
  • 进阶:Java 基本类型在 JVM 中的内存布局

整数仓库的四个货架

变量村的整数仓库里,老陈师傅指着四个大小不同的货架:

"绝大多数情况下你只用 intbyteshort 用在内存紧张的地方(比如嵌入式设备、网络协议解析)。long 只在数字可能超过 20 亿的时候用——long 的字面量末尾要加大写 L。"

java
// PrimitiveTypes.java
public class PrimitiveTypes {
    public static void main(String[] args) {
        byte b = 100;
        short s = 30000;
        int i = 1_000_000;          // Java 7 起可以用下划线分隔数字——纯语法糖
        long l = 3_000_000_000L;    // 超过 int 范围时必须加 L

        System.out.println("byte: " + b);
        System.out.println("short: " + s);
        System.out.println("int: " + i);
        System.out.println("long: " + l);
    }
}

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

byte: 100
short: 30000
int: 1000000
long: 3000000000

overflow——整数溢出的后果

如果往一个 int 里放超范围的数会发生什么?

java
int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max + 1); // 输出:-2147483648

"这不是 bug,这叫整数溢出。"二进制表示已经满了,再加 1 就像汽车的里程表从 999999 翻回 000000——值绕到了负数那一边。long 能存到 9 后面 18 个零,日常用几乎不会溢出。


小数银行的两个柜台

"小数有两种:"

  • float:4 字节,~7 位有效数字,字面量末尾必须加 fF
  • double:8 字节,~15 位有效数字,字面量加不加 d 都行
java
float pi = 3.1415f;  // 不加 f 会编译错误——3.1415 默认是 double
double e = 2.71828;   // 不加 d 没问题,double 是默认的

浮点数的大坑:算不准

java
double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 你以为输出 0.3

实际输出: 0.30000000000000004

"不是 0.3?" 我瞪大眼睛。

"不是。原因和 Java 无关——这是二进制浮点数的固有限制。0.1 在二进制里是一个无限循环小数,跟 1/3 在十进制里是 0.3333... 一样。你用 double 只能存一个近似值,多个近似值加起来误差就冒出来了。"

涉及金钱计算绝对不要floatdouble——后面学 BigDecimal 时再说。


字符驿站:char 不是字符串

java
char ch = 'A';   // ✅ char 用单引号包住
char ch2 = "A";  // ❌ 编译错误——双引号是字符串
char ch3 = 'AB'; // ❌ 编译错误——char 只能装一个字符

char 是一个 16 位的 Unicode 字符,底层是一个 0~65535 的数字。你可以把 char 当整数用:

java
char letter = 'A';
System.out.println((int) letter); // 输出:65('A' 的 Unicode 编码)

真假哨站:boolean

java
boolean isReady = true;
boolean isDone = false;

只有两个值:truefalse。在 Java 里,boolean 不能和整数相互转换——不像 C 语言那样把 0 当假、非 0 当真。


常见陷阱

陷阱一:整数除法丢失小数

java
int a = 5;
int b = 2;
System.out.println(a / b); // 输出:2,不是 2.5

两个整数相除,Java 做整数除法——直接舍去小数部分。如果你要小数结果,至少一个操作数要用小数类型:

java
System.out.println(5 / 2.0);       // 输出:2.5
System.out.println(5.0 / 2);       // 输出:2.5
System.out.println((double) 5 / 2); // 输出:2.5

陷阱二:long 字面量忘加 L

java
long big = 10000000000; // 编译错误:integer number too large

因为 10000000000 被编译器当作 int,但它超出了 int 范围。改正:

java
long big = 10000000000L; // 加 L 告诉编译器这是 long 字面量

陷阱三:float 字面量忘加 f

java
float f = 3.14; // 编译错误:incompatible types

3.14 默认是 double,不能隐式放进 float。改正:

java
float f = 3.14f;

陷阱四:中文标点符号

全角分号 、全角引号 "、全角括号 ()——这些在中文文本里看起来正常,但在 Java 代码里都是语法错误。写代码时输入法切到英文模式。


C++ 差异: C++ 的基本类型看起来和 Java 很像,但 int 大小不固定——16 位系统上是 2 字节,32/64 位上是 4 字节。Java 的 int 在任何平台上都是固定的 4 字节,跨平台一致性是 Java 的设计目标之一。

Python 差异: Python 没有 byteshortlong 的区别——只有一个 int,大小只受内存限制。char 也不存在——字符就是长度为 1 的字符串。而且 Python 的整数可以任意大,不存在溢出问题。


→ 下一步:类型转换

你认识了每种类型的"房间大小"。但程序里经常需要把数据从一种类型换到另一种类型——int 变成 doubledouble 变成 int。有些转换安全,有些会丢数据。

第2章续:类型转换

Built with VitePress | Software Systems Atlas