Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

    • Java概述
    • Java语法
    • 面向对象编程
    • Java数组
    • String字符串
    • 异常处理
    • 基本类型与包装类
      • 1. 基本类型
      • 2. 包装类型
      • 3. 基本类型与包装类型对比
      • 4. 自动装箱与拆箱
      • 5. 拆箱空指针
      • 6. 包装类缓存
      • 7. 数值转换
        • 7.1 自动类型提升
        • 7.2 强制类型转换
      • 8. 浮点数精度
      • 9. char 与 Unicode
      • 10. boolean
      • 11. 开发建议
      • Tips 快问快答
    • Object类与常用方法
    • 泛型
    • 枚举与注解
    • 反射
    • 值传递与引用
    • Lambda表达式与函数式接口
    • Stream API
    • Optional与空值处理
    • 日期时间API
    • Java现代语法特性
  • Java集合

  • Java并发

  • Java IO

  • JVM

目录

基本类型与包装类

Java 同时提供基本类型和包装类型。基本类型追求简单高效,包装类型让基本值可以作为对象参与泛型、集合、反射、注解、序列化等机制。

这一节要解决几个非常常见的问题:

  • int 和 Integer 到底有什么区别。
  • 自动装箱和拆箱是怎么发生的。
  • 为什么 Integer a = 127; Integer b = 127; a == b 可能是 true。
  • 为什么 Integer 拆箱会抛 NullPointerException。
  • 金额为什么不能用 double。

# 1. 基本类型

Java 有 8 种基本类型。

类型 位数 默认值 取值特点
byte 8 0 小范围整数
short 16 0 短整数
int 32 0 最常用整数
long 64 0L 大整数
float 32 0.0f 单精度浮点
double 64 0.0d 双精度浮点
char 16 '\u0000' Unicode 字符单元
boolean 未规定具体位数 false 布尔值

局部变量没有默认值,必须先赋值再使用:

public void test() {
    int value;
    System.out.println(value); // 编译失败
}

成员变量才有默认值:

public class Counter {
    private int count; // 默认 0
}

# 2. 包装类型

每种基本类型都有对应包装类。

基本类型 包装类型
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

包装类型是对象,可以为 null,可以放进集合和泛型中。

List<Integer> numbers = new ArrayList<>();
numbers.add(1);

不能写:

List<int> numbers = new ArrayList<>(); // 编译失败

泛型要求类型参数是引用类型,因此必须使用 Integer。

# 3. 基本类型与包装类型对比

对比项 基本类型 包装类型
是否对象 否 是
是否可为 null 否 是
存储开销 小 更大,有对象头
适合场景 高频计算、局部变量、数组 集合、泛型、可空字段、反射
比较方式 == 优先 equals
默认值 有固定默认值 成员变量默认 null

内存关系简化图:

int value = 10
┌────────────┐
│ value: 10  │  直接保存数值
└────────────┘

Integer number = 10
┌──────────────┐
│ number 引用   │
└──────┬───────┘
       ▼
┌──────────────┐
│ Integer 对象  │
│ value = 10   │
└──────────────┘

实际 JVM 会做很多优化,但从语言语义上可以这样理解。

# 4. 自动装箱与拆箱

自动装箱:基本类型自动转换为包装类型。

Integer value = 10;

大致等价于:

Integer value = Integer.valueOf(10);

自动拆箱:包装类型自动转换为基本类型。

Integer value = 10;
int number = value;

大致等价于:

int number = value.intValue();

转换流程:

int 10
  │ boxing
  ▼
Integer.valueOf(10)
  │
  ▼
Integer 对象
  │ unboxing
  ▼
intValue()
  │
  ▼
int 10

# 5. 拆箱空指针

包装类型为 null 时,自动拆箱会抛 NullPointerException。

Integer value = null;
int number = value; // NullPointerException

真实发生的是:

int number = value.intValue();

开发中最常见场景:

public boolean isEnabled(Boolean enabled) {
    return enabled; // enabled 为 null 时 NPE
}

更安全的写法:

public boolean isEnabled(Boolean enabled) {
    return Boolean.TRUE.equals(enabled);
}

或者在入参处明确默认值。

# 6. 包装类缓存

部分包装类会缓存常用值。以 Integer 为例,默认缓存 -128 到 127。

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true

Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false

原因:

Integer.valueOf(127)
  │
  ├─ 命中缓存:返回已有 Integer 对象
  ▼

Integer.valueOf(128)
  │
  ├─ 超出默认缓存:创建新对象
  ▼

不要依赖 == 比较包装类型数值,正确写法是:

Objects.equals(a, b);

或拆箱后比较,但要确保不为 null。

常见缓存:

包装类 常见缓存
Boolean TRUE、FALSE
Byte 全部缓存
Short 通常缓存 -128 到 127
Integer 默认 -128 到 127
Long 通常缓存 -128 到 127
Character 通常缓存 0 到 127
Float、Double 不缓存

# 7. 数值转换

# 7.1 自动类型提升

小范围整数可以自动转成大范围整数:

int a = 10;
long b = a;

整数运算中,byte、short、char 通常会提升为 int。

byte a = 1;
byte b = 2;
// byte c = a + b; // 编译失败
int c = a + b;

# 7.2 强制类型转换

大范围类型转小范围类型需要强转,可能溢出。

int value = 130;
byte b = (byte) value;
System.out.println(b); // -126

转换过程不是“报错”,而是截断高位。

int 130
二进制低 8 位保留
  │
  ▼
byte -126

开发中需要对外部输入做范围校验,不要盲目强转。

# 8. 浮点数精度

float 和 double 使用二进制浮点表示,不能精确表示很多十进制小数。

System.out.println(0.1 + 0.2); // 0.30000000000000004

金额计算不要使用 double:

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

不要这样创建金额:

new BigDecimal(0.1); // 不推荐

推荐:

new BigDecimal("0.1");
BigDecimal.valueOf(0.1);

# 9. char 与 Unicode

char 是 16 位 Unicode 代码单元,不一定等于一个完整字符。

char c = '中';

对于超出基本多文种平面的字符,一个视觉字符可能由两个 char 组成。

String emoji = "😀";
System.out.println(emoji.length()); // 2

这也是处理 Emoji、短信长度、昵称截断时容易出错的原因。

# 10. boolean

Java 的 boolean 只有 true 和 false,不能和数字互转。

boolean flag = true;
// int value = flag; // 编译失败

这与 C/C++ 不同,避免了很多隐式转换问题。

包装类型 Boolean 可以为 null,常用于数据库三态字段:

true  = 是
false = 否
null  = 未设置

但用于条件判断前必须处理 null。

# 11. 开发建议

场景 建议
局部计数、循环变量 使用基本类型
DTO 可空字段 使用包装类型
数据库字段映射 使用包装类型表达 null
集合元素 使用包装类型
高频数值计算 尽量避免频繁装箱
金额计算 使用 BigDecimal
包装类型比较 使用 Objects.equals

避免隐式装箱带来的性能问题:

Long sum = 0L;
for (long i = 0; i < 1000000; i++) {
    sum += i; // 频繁拆箱、装箱
}

更好:

long sum = 0L;
for (long i = 0; i < 1000000; i++) {
    sum += i;
}

# Tips 快问快答

Q:为什么 Java 要有基本类型? A:基本类型更简单高效,避免所有数值都变成对象造成额外内存和性能成本。

Q:为什么集合不能放 int? A:泛型类型参数必须是引用类型,所以要使用 Integer。

Q:自动装箱一定会创建新对象吗? A:不一定。Integer.valueOf 可能命中缓存。

Q:包装类型能用 == 比较吗? A:不建议。== 比较引用,缓存范围外结果可能和预期不同。

Q:Integer 拆箱为什么会 NPE? A:拆箱本质是调用 intValue(),如果引用为 null 就会空指针。

Q:金额为什么不用 double? A:二进制浮点无法精确表示很多十进制小数,金额应使用 BigDecimal 或以分为单位的整数。

Q:new BigDecimal(0.1) 为什么不推荐? A:传入的 0.1 已经是近似的 double 值,会把误差带进 BigDecimal。

Q:char 能表示所有字符吗? A:不能保证。某些字符需要两个 char 组成的代理对表示。

Q:Boolean 用在 if 中安全吗? A:如果可能为 null 就不安全,会自动拆箱并抛 NPE。

Q:什么时候字段用包装类型? A:当需要表达“未设置”或数据库 null 时,用包装类型更合适。

上次更新: 2026/06/24, 16:28:28
异常处理
Object类与常用方法

← 异常处理 Object类与常用方法→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式