跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Java 包装类与泛型核心解析

Java 包装类将基本数据类型封装为对象,支持装箱拆箱及自动转换机制。泛型提供类型安全与代码重用,通过类型擦除在运行时消除泛型信息。涵盖包装类映射、自动装箱原理、泛型定义与上界约束、泛型方法及通配符使用规则。

随缘发布于 2026/3/17更新于 2026/5/2423 浏览
Java 包装类与泛型核心解析

一、包装类

1.1. 基本类型和对应的包装类

Java 共有 8 种基本数据类型,Java 给这些基本类型都提供了一个类进行表示,来对这些类进行一个封装,这就是包装类。

基本类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

1.2. 装箱和拆箱

在 Java 当中,提供了一些操作,使包装类和内置类型可以相互转换。内置类型转为包装类型称为装箱,包装类型转为内置类型称为拆箱。但这些代码写法已经过时了,我们需要重点掌握的是自动装箱和自动拆箱。

1.3. 自动装箱和自动拆箱

public class Main {
    public static void main(String[] args) {
        int i = 10;
        Integer ii = i; // 自动装箱
        Integer ij = (Integer) i; // 自动装箱,后面的 (Integer) 可有可无
        int j = ii; // 自动拆箱
        int k = (int)ii; // 自动拆箱,后面的 (int) 可有可无
    }
}

我们可以通过 javap -c 查看字节码文件内容,观察装箱和拆箱的操作。我们可以在 IDEA 里面装一个 jclasslib ByteCode Viewer 的插件,然后点击 View,再点击 Show Bytecode With Jclasslib。我们点到 main 方法,点击 code,就可以看到所对应的字节码文件。

Image

Image

我们来看下面的一段代码,此时的 a,b,c,d,e 都是引用类型变量。当赋值相同时,结果就是 true;当赋值不同时,结果就是 false。当赋值超出包装类型的范围时,无论赋值相不相等,结果都是 false。

这是因为 Integer 里面的常量值放在常量池当中,我们进行赋值,相当于在常量池中进行取值,如果超出这个值,那么就是池内与池外的进行比较,结果就是 false。

public class Main {
    public static void main(String[] args) {
        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 e = 126;
        System.out.println(a == e); // false
    }
}

二、泛型的概念

很多编程语言都有泛型这样的语法机制。在 Java 中,写一个类或者是方法,需要声明方法里面的成员或者参数的类型。但也有些情况下,需要一个类或者方法能够多种类型支持。也就是一份代码,支持多种数据类型。

三、引出泛型

3.1. 语法规则

class 泛型名称<参数列表> {
    // 这里可以使用类型参数;
}
class ClassName<T1,T2,……,Tn> {}

参数列表中要把类中会用的哪些类型列出来,后续使用这个类,创建实例的时候也要同时指定泛型参数的实参。T1,T2 相当于类型的形参。

private T[] arrays = new T[]; // 这种写法是错误的

因为 T 要表示任何类型,new T[] 的时候就可能会涉及到该类的构造方法,T 是什么类型不知道该怎么办?就得先写成 Object[] 再进行强转。

T[] arrays = (T[]) new Object[10];
class MyArray<T> {
    T[] arrays = (T[]) new Object[10];
    public T get(int index) {
        return arrays[index]; // 获取数组的下标
    }
    public void set(int index, T value) {
        arrays[index] = value; // 对数组进行赋值
    }
}
// 上面的 T 不用再进行强转了
// 对方法的实现
public class Main {
    public static void main(String[] args) {
        MyArray<String> array1 = new MyArray<>(); // 里面可以存放字符。代码是灰色的,表示可以不写
        MyArray<Integer> array2 = new MyArray<>(); // 里面可以存放整数
        MyArray array4 = new MyArray(); // 裸类型,这种写法是不科学的
        // MyArray<int> array3 = new MyArray<>(); // error: Type argument cannot be of primitive type
    }
}

3.2. 泛型的优点

  1. 代码重用,一份代码,支持多种类型;
  2. 自动地进行类型转化,编译过程中会自动触发一些类型检查。

四、类型擦除

4.1. 擦除的机制

Java 的泛型,本质上是通过 Object 类进行编译的。编译器生成代码的时候,自动进行类型转化。比如下面的代码中的 get 方法,我要对 T 转化成 String 类型,编译器从数组中拿到的是一个 Object 类,然后进行自动转化成 String 类,返回到调用位置。在 set 方法里面,set String 进来,编译器再自动把 String 转化成 Object。

class MyArray<T> {
    T[] arrays = (T[]) new Object[10];
    public T get(int index) {
        return arrays[index];
    }
    public void set(int index, T value) {
        arrays[index] = value;
    }
}

下面是一段擦除的代码用例

// 擦除前
class MyArray<T> {
    public Object[] arrays = new Object[10];
    public T getPos(int pos) {
        return (T)this.arrays[pos];
    }
    public void setVal(int pos, T val) {
        this.arrays[pos] = val;
    }
}
// 擦除后
class MyArray<T> {
    public Object[] arrays = new Object[10];
    public Object getPos(int pos) {
        return this.arrays[pos];
    }
    public void setVal(int pos, T val) {
        this.arrays[pos] = val;
    }
}

五、泛型的上界

5.1. 泛型的上界的定义

描述的是使用泛型,创建泛型实例的时候,传入的参数(类型实参)需要满足什么条件。

5.2. 语法规则

class 泛型名称<类型实参 extends 类型边界> {}

这个类型边界相当于是'父类',后续创建类型实例的类型参数,必须是这个父类的子类。比如我们要写一个算术运算的泛型类,泛型参数必须给数字。

class MyArray<E extends Number> {
    MyArray<Integer> l1; // 正常
    MyArray<String> l2; // 错误
}

如果没有指定类型边界 E,可以视为 E extends Object。

六、泛型方法

6.1. 定义语法

方法限定符 <类型形参列表> 返回值类型 方法名称 {}

6.2. 交换方法的实例

public class Main {
    // 静态的泛型方法需要在 static 后面用<>声明泛型类型参数
    public static <E> void swap(E[] array, int i, int j) {
        E t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
}

七、通配符

前面的知识都是在定义泛型时涉及到的,通配符是针对泛型实例化的时候涉及到的。

class MyClass<T> {}
public class Main {
    public static void main(String[] args) {
        MyClass<Integer> obj1 = new MyClass<>();
        MyClass<String> obj2 = new MyClass<>();
        MyClass<Integer> obj3 = new MyClass<>();
        obj1 = obj3; // 正常
        obj1 = obj2; // 错误
    }
}

因为 Obj1 与 Obj2 类型不相同,所以会报错。那我们能否创建一种引用,能够指向多种泛型参数的对象呢?这时就要用到通配符了。

MyClass<?> obj4 = obj3;
MyClass<? extends Number> obj5 = obj1;
obj5 = obj2; // 这个代码不符合要求,约定 obj5 的通配符,只能匹配到 Number 和它的子类;
// 因为通配符只能在泛型实例化时使用

这里的代码不要和泛型的上界搞混。我们除了可以指定父类,还能指定子类。

MyClass<? super Integer> obj6 = obj1; // 此处的通配符只能匹配到 Integer 和它的父类
obj6 = new MyClass<double>(); // double 并不是 Integer 的子类,所以会报错
obj6 = new MyClass<Number>(); // Number 是 Integer 的父类。

目录

  1. 一、包装类
  2. 1.1. 基本类型和对应的包装类
  3. 1.2. 装箱和拆箱
  4. 1.3. 自动装箱和自动拆箱
  5. 二、泛型的概念
  6. 三、引出泛型
  7. 3.1. 语法规则
  8. 3.2. 泛型的优点
  9. 四、类型擦除
  10. 4.1. 擦除的机制
  11. 五、泛型的上界
  12. 5.1. 泛型的上界的定义
  13. 5.2. 语法规则
  14. 六、泛型方法
  15. 6.1. 定义语法
  16. 6.2. 交换方法的实例
  17. 七、通配符
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AI 时代的内容创作:从代码到认知的范式转移
  • MySQL 详细安装与配置完整教程
  • mdev 与 udev:嵌入式及桌面 Linux 设备管理对比
  • 7 款热门 Claude Skills 开源工具:GitHub 精选技能库
  • Python 遍历目录
  • 手写 C++ TCP 服务器:自定义协议与粘包处理实战
  • Python 纪念币预约自动化工具实现与部署
  • Verilog 实现半加器:FPGA 硬件入门实战
  • 鸿蒙游戏开发:AI 驱动的智能 NPC 实现体验
  • OpenClaw 本地部署飞书机器人配置指南
  • 前端函数防抖详解:原理、手写与 Lodash 实战
  • 使用双指针解决链表问题
  • 元迁移学习:快速适应新任务的方法与原理
  • Dify 集成 MySQL 实战:基于 MCP 协议的数据查询方案
  • 医疗 AI 可信系统全栈实现:向量索引与贝叶斯网络(下)
  • 金仓 KingbaseES 融合架构实践:从多库并存到一库多能
  • C++高性能事件循环库libev封装实战
  • 编写第一个 Rocket 0.5 Web 应用
  • Eclipse IDE Java 注解处理器 AnnotationMirror 示例
  • Java Lambda 和匿名内部类为何不能修改外部变量?final 与等效 final 解析

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online