news 2026/2/10 2:22:53

【Java核心】:一文搞懂包装类、泛型与PECS原则

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Java核心】:一文搞懂包装类、泛型与PECS原则

一、包装类

1.1 基本类型的痛点

Java 是一种面向对象的语言,但为了性能,保留了 int、double 等 8 种基本数据类型。然而,Java 的集合框架(如 ArrayList)要求所有存入的元素必须是对象(引用类型)。

这就导致了一个问题:我们无法直接写 List,因为 int 不是对象。

1.2 包装类的登场

为了解决这个问题,Java 给每种基本类型都提供了一个对应的包装类

基本数据类型特殊情况
intInteger
CharCharacter
其余首字母大写

1.3自动装箱和拆箱

装箱:基本类型→\rightarrow包装类。编译器自动调用

Integer。valueOf(520);

拆箱:包装类→\rightarrow基本类型。编译器自动调用

int num = a.intValue();

1.4面试题

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,两次 new }

Java 为了性能,对 Integer 做了缓存优化。

JVM 在启动时把 -128 到 127 这 256 个整数提前做成对象并放进数组,以后只要自动装箱的值落在这个区间,就直接把数组里现成的对象给你,不再 new。

如果数值在 -128 到 127 之间,自动装箱时会直接使用缓存池中的对象,所以 a 和 b 是同一个对象。

如果超出这个范围(如 128),每次都会 new 一个新对象,地址自然不同。

缓存只影响 == 比较,代码里比较包装类一律用 equals()就行

记忆:== 比“是不是同一个人”,equals() 比“长得是不是一样”。

二、泛型

2.1为什么要有泛型?

泛型(Generics)就是参数化类型。它就像给容器贴了一个标签,告诉编译器:“我这里只能装这种东西,别乱放。”ArrayList<Integer> 就是贴了“只能装整数”标签的瓶子。

没有泛型之前,取数据时必须强制类型转换,如 (String) obj,同时编译器不检查类型,万一你把 int 强转成 String,运行时会报ClassCastException

2.2语法

占位符 <T>:定义类时,我不知道将来要存什么,先用 T (Type) 占个座。

class MyArray<T> { // <T> 标志这是一个泛型类 public void set(T val) { ... } public T get() { ... } }

2.3 类型擦除

泛型最核心的原理:JVM 根本就不认识泛型。

编译时:编译器进行严格的类型检查。

class MyArray<T> { T data; }

编译后:泛型信息被擦除。所有的 <T>都会被替换成 Object(或者指定的上界)。

class MyArray { Object data; // T 变成了 Object }

这意味着,ArrayList 和 ArrayList 在运行时的类是完全一样的,都是 ArrayList。

三、泛型的通配符(难)

泛型虽然好用,但它是不兼容的。

3.1引进

即便 Apple 是 Fruit 的子类,List<Apple> 也不是 List<Fruit> 的子类。
接下来讲解一下:

定义一个方法:参数是 List<Fruit>

调用这个方法:试图传入 List<Apple>

它的参数声明是 List<Fruit>,意味着它接收一个装水果的列表。

// 这是一个接收“水果表”的方法 public static void processFruits(List<Fruit> fruits) { // 因为参数声明是 List<Fruit> // 所以在方法内部,Java 允许我往里 add 任何 Fruit 的子类 // 比如这里,我合法的 add 了一个香蕉 fruits.add(new Banana()); }

你手里有一个 List,你想把它传给上面的方法。

public static void main(String[] args) { // 1. 创建一个只能装苹果的 List List<Apple> appleList = new ArrayList<>(); appleList.add(new Apple()); // 2. 【报错发生在这里】 // 你想把 appleList 传给 processFruits 方法 // processFruits(appleList); 报错 }

我们看上面代码的冲突点:

1.看 processFruits 方法内部:

它拥有写入权限,调用了 fruits.add(new Banana())。

这是完全合法的,因为它的参数类型是 List<Fruit>(水果列表当然可以加香蕉)。

2.看 main 方法:

你传入的是 appleList(苹果列表)。

如果 Java 允许你传进去,那么 processFruits 方法里的那句 add(new Banana()),实际上就是在往你的苹果列表里塞香蕉。
总结:

方法定义方 (List<Fruit>) 说:我有权利往里放任何水果(包括香蕉)。

方法调用方 (List<Apple>) 说:我只能装苹果,绝对不能混进香蕉。

这两个承诺是冲突的。为了防止 processFruits 方法利用它的“大权限”破坏你“小范围”的列表,Java 在参数传递这一步就报错,毕竟总不能往苹果列表塞一个榴莲进去对吧


所以 Java 告诉你:它们是不兼容的类型,为了解决这个问题,Java 引入了通配符。

3.2上界通配符:<? extends Fruit>

含义:这个盘子装的是 Fruit 或者 Fruit 的子类 。

形象比喻:“水果列表”。我只知道里面是水果,但不知道具体是哪种。

能力限制:

能取 (Get):取出来的肯定是 Fruit,安全。

不能存 (Set):编译器禁止写入任何数据(除了 null),因为它怕你往苹果盘里塞香蕉 。

适用场景:生产者 (Producer),你需要从集合中读取数据。

3.3下界通配符:<? super Fruit>

含义:这个盘子装的是 Fruit 或者 Fruit 的父类 。

形象比喻:“水果回收站”。既然标准是“至少能装水果”,那你扔苹果、香蕉进去都行。

能力限制:

能存 (Set):可以往里存 Fruit 及其子类。

难取 (Get):取出来的数据丢失了类型信息,只能当做 Object 处理 。

适用场景:消费者 (Consumer),你需要往集合里写入数据。

3.4 PECS 原则

Producer Extends:你要读,用 extends。 Consumer Super:你要写,用 super

四、 总结

包装类解决了基本类型无法放入集合的问题,但要注意 -128~127 的缓存坑。

泛型提供了编译期的类型安全,但底层是通过类型擦除实现的。

通配符解决了泛型不兼容的问题。遇到 ? 时,牢记 PECS 原则,不要试图往 extends 容器里存东西,也不要指望从 super
容器里取出具体类型

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/3 3:03:23

医院HIS系统如何集成百度编辑器实现PDF病历跨平台编辑?

Word文档导入与粘贴功能解决方案 项目背景与需求分析 作为安徽某IT公司的.NET工程师&#xff0c;我最近负责在企业网站后台管理系统中增加Word粘贴和文档导入功能。客户的核心需求是&#xff1a; Word粘贴功能&#xff1a;直接从Word复制内容到网站编辑器&#xff0c;图片自…

作者头像 李华
网站建设 2026/2/3 12:39:24

保险网页项目怎么用javascript实现文件夹上传及加密?

大文件传输解决方案技术方案 作为陕西某软件公司项目负责人&#xff0c;针对公司产品部门提出的大文件传输需求&#xff0c;我经过深入调研和技术评估&#xff0c;提出以下专业解决方案。 一、需求分析与技术挑战 核心需求 支持50G以上大文件传输&#xff0c;包含文件/文件…

作者头像 李华
网站建设 2026/2/5 16:23:25

文件时间属性修改神器,绝了

有的时候需要对文件的时间属性进行修改&#xff0c;例如文件的创建时间、访问时间和或者最后的修改时间。 但是Windows系统里面自带的工具没有办法修改这些参数&#xff0c;需要借助第三方软件。今天给大家推荐两款非常强大的软件&#xff0c;可以帮助修改文件时间。 JD Design…

作者头像 李华
网站建设 2026/2/7 12:28:44

25.C++进阶:map|pair类型|构造|增删查|数据修改|迭代器|multimap|OJ

map系列的使⽤ map和multimap参考⽂档 参考文档 map类的介绍 map的声明如下&#xff0c;Key就是map底层关键字的类型&#xff0c;T是map底层value的类型&#xff0c;set默认要求Key⽀持⼩于⽐较&#xff0c;如果不⽀持或者需要的话可以⾃⾏实现仿函数传给第⼆个模版参数&am…

作者头像 李华
网站建设 2026/2/3 12:39:23

django微信小程序-基于python的服装穿搭推荐系统

目录摘要技术栈开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;摘要 随着移动互联网的快速发展&#xff0c;微信小程序凭借其轻量级、无需安装的特点成为用户获取服务的重要入口。基于Pytho…

作者头像 李华