Skip to content
第 5 / 250 章后端⏱ 10 分钟阅读

第 5 章:八种基本数据类型

学习目标

  • 掌握 Java 8 种基本数据类型的字节数、取值范围
  • 理解整数默认 int、浮点默认 double 的设计原因
  • 了解字符编码(ASCII / Unicode / UTF-8)底层原理
  • 避免基本类型使用的常见坑

一、Java 的 8 种基本类型

Java 只有 8 种基本数据类型(Primitive Types),分三大类:

二、8 种类型速查表

类型字节位数取值范围默认值包装类
byte18-128 ~ 1270Byte
short216-32,768 ~ 32,7670Short
int432-2³¹ ~ 2³¹-1(约 ±21 亿)0Integer
long864-2⁶³ ~ 2⁶³-10LLong
float432约 ±3.4×10³⁸(7 位有效数字)0.0fFloat
double864约 ±1.8×10³⁰⁸(15 位有效数字)0.0dDouble
char2160 ~ 65,535(Unicode 字符)'\u0000'Character
boolean--true / falsefalseBoolean

字节数可视化

记忆口诀:byte < short < int < long(按字节数从小到大),float = int(4 字节),double = long(8 字节),char = short(2 字节)。

三、整数类型

3.1 四种整数的字节数与范围

java
// byte: -128 ~ 127
byte b1 = 100;
byte b2 = -128;
byte b3 = 127;
// byte b4 = 128;    // ❌ 编译报错:超出 byte 范围

// short: -32,768 ~ 32,767
short s1 = 30000;
short s2 = -32768;
// short s3 = 50000;  // ❌ 编译报错

// int: 约 ±21 亿(最常用)
int i1 = 2000000000;
int i2 = -2_000_000_000;  // Java 7+ 支持下划线分隔,便于阅读
// int i3 = 3000000000;   // ❌ 编译报错:超过 int 范围

// long: 极大范围(需要加 L 后缀)
long l1 = 100L;
long l2 = 9000000000L;    // ✅ 90 亿,需要 L 后缀
// long l3 = 9000000000;   // ❌ 编译报错:默认是 int,超出 int 范围

3.2 为什么默认是 int?

Java 设计者认为:int 是 32 位 CPU 原生支持的速度最快的整数类型

java
// 整数默认是 int
int x = 100;     // 100 被识别为 int
// long y = 100; // OK,自动从 int 转为 long(小到大自动转)
// long z = 9000000000; // ❌ 9000000000 默认是 int,超出范围
long z = 9000000000L;  // ✅ 加 L 表示是 long

整数后缀

  • longLl(推荐 L,因为 l 容易和数字 1 混淆)
  • 没有 int 后缀,默认就是 int

3.3 整数的三种进制

java
int decimal = 100;        // ① 十进制(默认)
int hex = 0xFF;           // ② 十六进制:255(0x 前缀)
int octal = 077;          // ③ 八进制:63(0 前缀,注意不是 O)
int binary = 0b1010;      // ④ 二进制:10(0b 前缀,JDK 7+)

输出验证:

java
System.out.println(decimal);  // 100
System.out.println(hex);      // 255
System.out.println(octal);    // 63
System.out.println(binary);   // 10

3.4 下划线分隔符(Java 7+)

java
int creditCardNumber = 1234_5678_9012_3456;   // ① 信用卡号
long socialSecurityNumber = 999_99_9999L;     // ② 社保号
int hexWithUnderscore = 0xFF_EC_DE_5E;        // ③ 字节对齐

规则:只能在数字之间,不能在开头、末尾、小数点前后。

java
// ❌ 错误用法
// int x = _100;        // 不能在开头
// int y = 100_;        // 不能在末尾
// double z = 3_.14;    // 不能在小数点后
// double w = 3._14;    // 不能在小数点前

四、浮点类型

4.1 float vs double

java
// double:双精度,约 15 位有效数字(默认,推荐)
double d1 = 3.141592653589793;
double d2 = 1.7976931348623157E308;   // 科学计数法

// float:单精度,约 7 位有效数字(需要加 f 后缀)
float f1 = 3.14f;
float f2 = 1.4E-45f;

4.2 精度对比实验

java
double d = 0.1 + 0.2;
System.out.println(d);  // 0.30000000000000004(不是 0.3!)

float f = 0.1f + 0.2f;
System.out.println(f);  // 0.3(float 也有误差,但显示不同)

浮点数不能精确表示小数!

这是 IEEE 754 浮点数的本质问题。金融计算绝对不能用 float/double,必须用 BigDecimal

java
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b));  // 0.3 精确

4.3 为什么默认是 double?

java
double x = 3.14;   // 3.14 被识别为 double
// float y = 3.14;  // ❌ 编译报错:double 转 float 精度损失
float y = 3.14f;   // ✅ 加 f 才是 float

原因:现代 CPU 普遍支持 64 位双精度运算,double 是性能与精度的平衡点。

4.4 三个特殊的浮点值

java
double positiveInfinity = 1.0 / 0.0;   // +Infinity
double negativeInfinity = -1.0 / 0.0;  // -Infinity
double notANumber = 0.0 / 0.0;         // NaN

System.out.println(positiveInfinity);  // Infinity
System.out.println(negativeInfinity);  // -Infinity
System.out.println(notANumber);        // NaN
System.out.println(Double.isNaN(notANumber));  // true

五、字符类型 char

5.1 char 本质上是整数

char16 位无符号整数,取值范围 0 ~ 65535,对应 Unicode 字符集。

java
char c1 = 'A';           // 字符字面量
char c2 = 65;            // ASCII 码:65 = 'A'
char c3 = '\u0041';      // Unicode:'\u0041' = 'A'
char c4 = '中';           // 直接赋值中文
char c5 = '\u4e2d';      // Unicode:'中' 的编码是 4E2D

System.out.println(c1);  // A
System.out.println(c2);  // A
System.out.println(c3);  // A
System.out.println(c4);  // 中
System.out.println(c5);  // 中

5.2 字符编码的演进

为什么 Java 的 char 是 2 字节?

因为 Java 诞生时(1995)Unicode 还只有 65,536 个字符(Basic Multilingual Plane,BMP),用 16 位(2 字节)刚好够用。

但后来 Unicode 扩展到了超过 14 万字符,需要用 4 字节(代理对)。Java 5 引入了 int 码点 来表示完整的 Unicode:

java
// 简单字符(一个 char)
char c = 'A';   // 单个 16 位

// 辅助平面字符(两个 char = 一个码点)
String emoji = "😀";  // 这个 emoji 实际是 2 个 char
int codePoint = emoji.codePointAt(0);  // 128512
System.out.println(codePoint);  // 128512

// 字符数(码点数)而不是 char 数
System.out.println(emoji.length());                   // 2(char 长度)
System.out.println(emoji.codePointCount(0, emoji.length()));  // 1(码点长度)

5.3 转义字符

java
char newline = '\n';      // 换行 LF(Unix)
char carriageReturn = '\r'; // 回车 CR(老 Mac)
char tab = '\t';          // 制表符
char backslash = '\\';    // 反斜杠本身
char singleQuote = '\'';  // 单引号本身
char doubleQuote = '\"';  // 双引号本身
char nullChar = '\0';     // 空字符
char unicode = '\u0041';  // Unicode 字符(4 位 16 进制)

六、布尔类型 boolean

Java 的 boolean 只有两个值:true / false

java
boolean isActive = true;
boolean hasPermission = false;
boolean isAdult = age >= 18;  // 表达式结果

6.1 重要:boolean 不参与数值运算

java
// ❌ C/C++ 中常见用法(Java 不允许)
// int x = true;          // 编译报错:boolean 不能转 int
// boolean flag = 1;      // 编译报错:int 不能转 boolean

// ✅ 正确写法
boolean flag = (x > 0);    // 表达式结果

6.2 boolean 在内存中的大小

JVM 规范没有明确规定 boolean 占多少字节,实际实现:

java
boolean flag = true;                    // 占 4 字节
boolean[] flags = new boolean[1000];    // 占 1000 字节(每个 1 字节)

七、类型转换

7.1 自动类型转换(小 → 大)

java
byte b = 10;
short s = b;     // 自动转换:byte → short
int i = s;       // 自动转换:short → int
long l = i;      // 自动转换:int → long
float f = l;     // 自动转换:long → float(注意:可能损失精度)
double d = f;    // 自动转换:float → double

7.2 强制类型转换(大 → 小)

java
double d = 3.14;
int i = (int) d;    // 强制转换:3.14 → 3(小数部分丢失)

long l = 100L;
int i2 = (int) l;   // 强制转换:100L → 100

int bigNum = 200;
byte b = (byte) bigNum;  // 强制转换:200 → -56(高位截断!)

7.3 转换时的精度损失

java
// 浮点转整数:直接截断小数部分(不四舍五入)
double d1 = 3.9;
int i1 = (int) d1;       // 3(不是 4)

// 大整数转小整数:高位截断
int i2 = 0x12345678;
byte b2 = (byte) i2;     // 0x78(只剩最低 8 位)

// 整数转浮点:可能损失精度
long l3 = 123456789012345L;
double d3 = l3;          // 1.23456789012345E14(精度损失)

警惕类型转换的坑

  1. 整数除法会丢失小数部分:5 / 2 = 2(不是 2.5)
  2. 浮点默认 double,赋值给 float 要加 f
  3. 长整数超过 int 范围必须加 L
  4. 强制转换可能造成数据丢失

八、为什么 Java 不支持无符号类型?

Java 的整数类型全部是有符号(signed),这是设计选择。

语言无符号支持
C / C++支持 unsigned int
Java不支持(除 char)
Go支持 uint

Java 不支持的原因

  1. 跨平台考虑:无符号类型在不同 CPU 上的行为不一致
  2. 简化设计:减少类型数量,降低学习成本
  3. 业务场景少:99% 的业务代码不需要无符号

替代方案

如果需要表示大数字(如文件大小、位运算标志),使用 long

java
long maxFileSize = Long.MAX_VALUE;  // 9.2 × 10^18

九、完整代码示例

java
/**
 * 基本数据类型综合示例
 *
 * 配套文档:第 5 章 八种基本数据类型
 * 运行方式:javac PrimitiveTypesDemo.java && java PrimitiveTypesDemo
 */
public class PrimitiveTypesDemo {
    public static void main(String[] args) {
        // ============ 整数类型 ============
        byte byteVar = 127;                         // ① 字节(-128 ~ 127)
        short shortVar = 32767;                    // ② 短整型(-32768 ~ 32767)
        int intVar = 2147483647;                    // ③ 整型(约 ±21 亿,最常用)
        long longVar = 9223372036854775807L;        // ④ 长整型(注意 L 后缀)

        System.out.println("=== 整数类型 ===");
        System.out.println("byte: " + Byte.MIN_VALUE + " ~ " + Byte.MAX_VALUE);
        System.out.println("short: " + Short.MIN_VALUE + " ~ " + Short.MAX_VALUE);
        System.out.println("int: " + Integer.MIN_VALUE + " ~ " + Integer.MAX_VALUE);
        System.out.println("long: " + Long.MIN_VALUE + " ~ " + Long.MAX_VALUE);

        // ============ 浮点类型 ============
        float floatVar = 3.14f;                     // ⑤ 单精度(注意 f 后缀)
        double doubleVar = 3.141592653589793;       // ⑥ 双精度(默认,推荐)

        System.out.println("\n=== 浮点类型 ===");
        System.out.println("float: " + Float.MIN_VALUE + " ~ " + Float.MAX_VALUE);
        System.out.println("double: " + Double.MIN_VALUE + " ~ " + Double.MAX_VALUE);
        System.out.println("0.1 + 0.2 = " + (0.1 + 0.2));  // 经典精度问题

        // ============ 字符类型 ============
        char charVar1 = 'A';                        // ⑦ 字符字面量
        char charVar2 = 65;                         // ⑧ ASCII 码
        char charVar3 = '\u4e2d';                   // ⑨ Unicode
        char charVar4 = '中';                       // ⑩ 直接赋值中文

        System.out.println("\n=== 字符类型 ===");
        System.out.println("'A' = " + charVar1);
        System.out.println("65 = " + charVar2);
        System.out.println("'\\u4e2d' = " + charVar3);
        System.out.println("'中' = " + charVar4);

        // ============ 布尔类型 ============
        boolean isJavaFun = true;                   // ⑪ 布尔
        boolean isFishTasty = false;

        System.out.println("\n=== 布尔类型 ===");
        System.out.println("Java 有趣吗? " + isJavaFun);
        System.out.println("鱼好吃吗? " + isFishTasty);

        // ============ 类型转换 ============
        System.out.println("\n=== 类型转换 ===");

        // 自动转换(小 → 大)
        int intVal = 100;
        long longVal = intVal;                      // ⑫ 自动 int → long
        double doubleVal = longVal;                 // ⑬ 自动 long → double

        System.out.println("int → long: " + longVal);
        System.out.println("long → double: " + doubleVal);

        // 强制转换(大 → 小)
        double pi = 3.14159;
        int truncatedPi = (int) pi;                 // ⑭ 强制 double → int(截断小数)
        System.out.println("double → int(截断): " + truncatedPi);

        // 整数除法截断
        int result = 5 / 2;                         // ⑮ 整数除法:2.5 → 2
        System.out.println("5 / 2 = " + result);

        double correctResult = 5.0 / 2;             // ⑯ 浮点除法:2.5
        System.out.println("5.0 / 2 = " + correctResult);
    }
}

运行结果

=== 整数类型 ===
byte: -128 ~ 127
short: -32768 ~ 32767
int: -2147483648 ~ 2147483647
long: -9223372036854775808 ~ 9223372036854775807

=== 浮点类型 ===
float: 1.4E-45 ~ 3.4028235E38
double: 4.9E-324 ~ 1.7976931348623157E308
0.1 + 0.2 = 0.30000000000000004

=== 字符类型 ===
'A' = A
65 = A
'\u4e2d' = 中
'中' = 中

=== 布尔类型 ===
Java 有趣吗? true
鱼好吃吗? false

=== 类型转换 ===
int → long: 100
long → double: 100.0
double → int(截断): 3
5 / 2 = 2
5.0 / 2 = 2.5

十、常见面试题

Q1: 为什么 int 是最常用的整数类型?

  1. CPU 原生支持:32 位 CPU 运算 int 最快
  2. 范围足够:约 ±21 亿能覆盖 99% 业务
  3. JVM 优化:int 在 JVM 字节码里有专门的 iaddimul 指令

Q2: float 和 double 怎么选?

场景推荐
科学计算 / 图形 / 游戏double(精度更高)
大数据量(如机器学习的特征)float(节省一半内存)
金融 / 货币计算BigDecimal(精确小数)

Q3: char 能不能存中文?

可以,但有坑

  • ✅ BMP 平面(基本中日韩)的字符:char c = '中'; 没问题
  • ❌ 辅助平面(部分罕见汉字、emoji):需要用 String 存代理对
java
// ✅ BMP 字符
char c = '中';  // 单个 char

// ❌ 辅助平面字符(如 emoji)
// char e = '😀';  // 编译报错:字面量超出 char 范围
String emoji = "😀";  // 用 String,存的是代理对

Q4: 不用 BigDecimal 怎么四舍五入?

java
double d = 3.7;
long rounded = Math.round(d);  // 4(四舍五入返回 long)

金融计算必须用 BigDecimal,浮点四舍五入仍有精度问题。

十一、本章小结

要点关键
8 种基本类型byte / short / int / long / float / double / char / boolean
整数默认 int大字面量必须加 L
浮点默认 doublefloat 必须加 f 后缀
char 是 16 位Unicode 编码,但 emoji 需要 String
boolean 不参与数值不能与 int 互转
自动转换小 → 大,无需操作
强制转换大 → 小,可能精度损失

动手练习

练习 1:基础题

声明并打印所有 8 种基本类型的极值:

java
System.out.println("byte 范围: " + Byte.MIN_VALUE + " ~ " + Byte.MAX_VALUE);
// ... 其他 7 种类型

练习 2:精度问题实验

java
System.out.println("0.1f + 0.2f = " + (0.1f + 0.2f));   // 浮点
System.out.println("(int)3.99 = " + (int)3.99);        // 截断
System.out.println("(int)-3.99 = " + (int)-3.99);      // 截断(不是四舍五入!)
System.out.println("5 / 2 = " + (5 / 2));              // 整数除法
System.out.println("5.0 / 2 = " + (5.0 / 2));          // 浮点除法

练习 3:挑战题

写一个 SafeCast.java,安全地将 doubleint四舍五入而不是截断。

提示:用 Math.round() 返回 long,再强转 int

java
double d1 = 3.4;
double d2 = 3.6;
System.out.println(safeCast(d1));  // 3
System.out.println(safeCast(d2));  // 4

推荐阅读


下一章第 6 章:自动装箱与拆箱

你已经完成了

  • ✅ 掌握 8 种基本类型的字节数和取值范围
  • ✅ 理解整数默认 int、浮点默认 double 的设计原因
  • ✅ 了解字符编码演进(ASCII → Unicode → UTF-8)
  • ✅ 掌握自动转换和强制转换规则
  • ✅ 警惕基本类型的常见坑(精度损失、整数除法等)

本站基于 VitePress 构建 · 由 Codebook 团队维护