[简单粗暴]一文彻底搞懂Java泛型中的PECS原则(在坑里躺了多年终于爬出来了)

[简单粗暴]一文彻底搞懂Java泛型中的PECS原则(在坑里躺了多年终于爬出来了)

两种限定通配符

  1. 表示类型的上界,格式为:<? extends T>,即类型必须为T类型或者T子类
  2. 表示类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类

PECS原则

生产者只能用extends,消费者只能用super

上代码

public class Fruit {
}
public class Apple extends Fruit{
}
public class Banana extends Fruit{
}

List<? extends Fruit> list 的理解

正如表面意思<? extends Fruit>表示的是泛型的类型是Fruit或者Fruit的子类,也就是说我们给list赋值时泛型可以写成Fruit或者Fruit的子类,可以是 new ArrayList(),也可以是new ArrayList(),还可以是new ArrayList()

看有些地方说"<? extends Fruit>表示list中的元素可能是Fruit或者Fruit的子类",感觉这种说法很有问题,

private static List<? extends Fruit> getExtendsList() {
    List<? extends Fruit> list;
    // Explicit type argument Fruit can be replaced with <> 意思就是new ArrayList<Fruit>() 可以写成 new ArrayList<>()
    list = new ArrayList<Fruit>();
    list = new ArrayList<Apple>();
    list = new ArrayList<Banana>();
    return list;
}

list的具体定义是new ArrayList(), new ArrayList(),还是new ArrayList(),在m1中是不知道的,最大的泛型是new ArrayList(),所以取出来的一定是Fruit,最小泛型new ArrayList(),new ArrayList()…可能有很多个,具体是哪个没办法确定,所以也没办法往里面添加元素

private static void m1( List<? extends Fruit> list) {
    Apple apple = new Apple();
    // 有可能list的定义是 list = new ArrayList<Banana>(),所以往里面添加Apple就会有问题
    // list.add(apple);
}

List<? super Fruit> list的理解

正如表面意思,泛型的类型是Fruit或者Fruit的父类,也就是我们给list赋值时泛型可以写Fruit或者Fruit的父类,可以是new ArrayList()也可以是 new ArrayList();

如果理解成"list中的元素是Fruit或Fruit的父类,仔细品品,漏洞百出,试想如果Fruit是个顶级接口呢?那岂不是list中只能放Object了?而且还只能是Object类本身?"

private static List<? super Fruit> getSuperList() {
    List<? super Fruit> list;
    list = new ArrayList<Fruit>();
    list = new ArrayList<Object>();
    return list;
}

list的具体定义到底是new ArrayList()或者new ArrayList()在m2方法中是没法确定的,所以往list中添加元素只能按照最小泛型处理,即按照new ArrayList()处理,获取元素时按照最大的泛型处理,即new ArrayList(),所以拿到的元素都是Object(都Object了,泛型也就没意义了),所以<? super Fruit>的意义在于往集合中添加元素,也就是"消费者只能用super"

private static void m2( List<? super Fruit> list) {
    Apple apple = new Apple();
    list.add(apple);
    Banana banana = new Banana();
    list.add(banana);
}

总结

  1. List<? extends Fruit> list 限定通配符泛型(还不确定的泛型,但是有范围),一般用于只获取
  2. List<? super Fruit> list 限定通配符泛型(还不确定的泛型,但是有范围), 一般用于只添加(也可以获取,但是获取出来的是Object,没啥意义)
  3. List list 明确的泛型,可获取,也可添加,也是我们用的最多的泛型

JDK中的PECS

java.util.Collections#copy

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
    int srcSize = src.size();
    if (srcSize > dest.size())
        throw new IndexOutOfBoundsException("Source does not fit in dest");

    if (srcSize < COPY_THRESHOLD ||
        (src instanceof RandomAccess && dest instanceof RandomAccess)) {
        for (int i=0; i<srcSize; i++)
            dest.set(i, src.get(i));
    } else {
        ListIterator<? super T> di=dest.listIterator();
        ListIterator<? extends T> si=src.listIterator();
        for (int i=0; i<srcSize; i++) {
            di.next();
            di.set(si.next());
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/487429.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(一)基于IDEA的JAVA基础8

使用多重if选择结构 多个if条件进行判断: 语法: if(条件1){ 执行语句1&#xff1b; }else if(条件2){ 执行语句2&#xff1b; }else if(条件3){ 执行语句3&#xff1b; }else if (条件4)…… 流程图: 我们来写个好玩的&#xff0c;对暗号: public class Test01 { …

【浅尝C++】类和对象第二弹=>类的6个默认成员函数/运算符重载详谈

&#x1f3e0;专栏介绍&#xff1a;浅尝C专栏是用于记录C语法基础、STL及内存剖析等。 &#x1f6a9;一些备注&#xff1a;之前的文章有点杂乱&#xff0c;这里将前面的知识点重新组织了&#xff0c;避免了过多冗余的废话。 &#x1f3af;每日努力一点点&#xff0c;技术变化看…

电阻器标记方法全解析:如何正确标注电阻器的阻值?

电阻器是一种用来限制电流流动的电子元件。它的主要作用是产生电阻&#xff0c;以控制电流的大小&#xff0c;从而保护其他电子元件不受过大的电流损害。电阻器通常由导电材料制成&#xff0c;电流在流过电阻器时会遇到阻力而产生电压降&#xff0c;使得电流被限制在一个较低的…

水牛社五大赚钱栏目概览:轻松了解项目核心与赚钱原理

很多新用户首次访问水牛社官网时&#xff0c;可能会感到有些迷茫。由于软件介绍相对较长&#xff0c;部分朋友可能缺乏耐心细读。然而&#xff0c;若您真心希望在网络上找到赚钱的机会&#xff0c;深入了解我们的发展历程将大有裨益。简而言之&#xff0c;本文旨在快速带您领略…

C++ assert()函数用法案例详解

参考:https://www.jb51.net/article/222176.htm assert宏的原型定义在<assert.h>中&#xff0c;其作用是如果它的条件返回错误&#xff0c;则终止程序执行。 原型定义&#xff1a; #include <assert.h> void assert( int expression );assert的作用是先计算表达…

【开发环境搭建篇】Redis服务器端安装和配置

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过大学刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0…

kubernetes最小调度单元Pod概述

Pod概述 一.Pod的概念1.Pod是什么2.Pod网络共享实现方式3.Pod存储共享方式4.创建Pod的流程 二.使用YAML文件定义Pod资源1.Pod资源清单YAML文件书写技巧1.YAML语法格式&#xff1a;2.配置Linux tab缩进两个空格3.使用kubectl explain帮助命令 2.创建Pod及Pod常用命令1.创建Pod资…

(免费领源码)Java#SSM#MYSQL学生信息管理系统的设计与实现70168-计算机毕业设计项目选题推荐

摘 要 从20年代开始&#xff0c;计算机疯狂的出现在人们的生活以及工作当中&#xff0c;成为人们生活、工作的好帮手&#xff0c;计算机深入到每家每户当中&#xff0c;网络办公&#xff0c;网络教学更是替换了传统手工记录管理的方式&#xff0c;使用计算机办公可以不必局限于…

Map中的computeIfAbsent()方法

调用java集合Map.computeIfAbsent()方法 java版本JDK1.8中&#xff0c;Map是我们经常使用的&#xff0c;在面对复杂Map时&#xff0c;我们怎么更好的去维护呢&#xff1f; 比如&#xff0c;这里的复杂Map&#xff0c;即<K,V>中V是一个Collection集合&#xff1a; 我们先…

Linux常用操作命令(清单快查版)

Linux常用操作命令&#xff0c;今日先给出快查清单&#xff0c;后续出带命令参数及不同OS的区别语法的相关示例 1. 文件与目录操作 命令描述ls列出目录内容cd切换目录pwd显示当前工作目录mkdir创建目录rmdir删除空目录cp复制文件或目录mv移动或重命名文件或目录rm删除文件或目…

Linux 的 app :一般到哪里下载 ?(**)

利用 appimagetool 工具对开发好的项目进行打包 &#xff08;***带笔记*&#xff09; https://blog.csdn.net/ken2232/article/details/131313613 1. 首选&#xff0c;直接通过 OS发行版的官网仓库&#xff1a;简单、方便&#xff1b;可能相对最可靠。 如&#xff1a; sudo a…

详解华为软件研发管理IPD

IPD,即集成产品开发(Integrated Product Development),是一种综合多种管理模型和理论、企业最佳实践的管理体系。旨在帮助企业快速适应市场变化,缩短产品上市时间,减少资源浪费,并提高生产力,以实现商业成功。 IPD的核心是跨部门团队的合作,涉及市场、研发、制造、服…

基于Redis实现短信登录

1.7.3、整体访问流程 当注册完成后&#xff0c;用户去登录会去校验用户提交的手机号和验证码&#xff0c;是否一致&#xff0c;如果一致&#xff0c;则根据手机号查询用户信息&#xff0c;不存在则新建&#xff0c;最后将用户数据保存到redis&#xff0c;并且生成token作为red…

Java项目:73 ssm档案管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 角色&#xff1a;管理员、用户 用户点击进入到系统操作界面&#xff0c;可以对个人中心、警察信息管理、事故信息管理、申诉信息管理等功能模…

Android开发 --- Android12外部存储权限问题

1.问题 Android12使用如下权限&#xff0c;将不会获得读写文件的权限 <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE" /> 2.解决 if (!Environment.isExternalStorageManager()) {Intent intent new Intent(Settings.ACTION_M…

pikachu靶场第十四关——XSS(跨站脚本)之js输出(附代码审计)

源代码&#xff1a; //这里讲输入动态的生成到了js中,形成xss //javascript里面是不会对tag和字符实体进行解释的,所以需要进行js转义//讲这个例子主要是为了让你明白,输出点在js中的xss问题,应该怎么修? //这里如果进行html的实体编码,虽然可以解决XSS的问题,但是实体编码后…

redis在docker安装并启动流程

1、启动server docker run -d -p 6379:6379 --name redis01 redis:7.2.4以上命令&#xff0c;每次启动新的Redis容器&#xff0c;数据会丢失。 我们需要挂载数据文件&#xff0c;在宿主机上面&#xff0c;这样就可以持久化数据. 2、挂载数据文件&#xff08;可根据需求选择…

Schemdraw小白从入门到放弃---原理工具书

文章目录 序版本最简单的例子一、总体思路二、元件2.1 color习题 2.2 label2.3 length 三、元件的连接3.1 延续性习题 3.2 方向习题 3.3 接线点习题3.3.1 默认激活anchor与沉默anchor3.3.2 切换鼠标焦点机制3.3.2.1 at函数规定元件的start接在哪个anchor上3.3.2.2 to函数规定元…

SpringBoot请求WebService服务接口

目录 确定请求接口是否为webService接口 请求对方的接口地址获取对方的wsdl文件 将wsdl文件转换成Java类 请求对方接口 请求方式一 请求方式二 确定请求接口是否为webService接口 接口地址类似于&#xff1a;http://172.0.0.1:8080/webservice/baseService?wsdl 这样的就…

智能合约 之 ERC-721

ERC-721&#xff08;Non-Fungible Token&#xff0c;NFT&#xff09;标准 ERC-721是以太坊区块链上的一种代币标准&#xff0c;它定义了一种非同质化代币&#xff08;Non-Fungible Token&#xff0c;NFT&#xff09;的标准。NFT是一种加密数字资产&#xff0c;每个代币都具有独…
最新文章