泛型除了KTV,还有一个让人比较疑惑的玩意,而且它就是用来表达疑惑的:?

虽然通过泛型已经达到我们想要的效果了,例如:

List<String> list = new ArrayList<String>();

这样就可以放心地存取String类型的数据。

但是(抱歉,凡事总有个但是),应用的场景总是在不断增加的。某一天:

老板:咱们之前给客户开发的功能中有个地方要改一改。

神牛:哪里要改呢?

老板:以前你写的代码List<Cat> list = new ArrayList<Cat>();只能列出Java宠物店托管的猫咪,但是现在Java宠物店已经扩大了经营范围,希望列出他们保管所有的宠物,只要是宠物就行......

神牛:这个easy!

老板:真的吗?

于是,神牛一通操作,代码就改成了这样:

class Cat extends Pets {};

class Dog extends Pets {};

public static void main(String[] args) {
List<? extends Pets> list = new ArrayList<Pets>();
Pets pets = list.get(0);
Cat cat = (Cat)list.get(1);
Dog dog = (Dog)list.get(2);
}

然鹅,过了一段时间,Java宠物店由于经营不善,已经将之前的宠物转卖、送人了一部分,现在就剩一些猫科动物,所以现在的宠物笼子需要重新分配,只要是猫科动物就要往里放。以前写的代码

List<? extends Pets> list = new ArrayList<Pets>();

就满足不了给宠物分配笼子的需求了(先想一想为啥不行了?)

神牛继续把键盘一顿猛敲,代码又改成了这样:

class Felidae {};
class Cat extends Felidae {}; public static void main(String[] args) {
List<? super Felidae> list = new ArrayList<Felidae>();
Cat cat = new Cat();
list.add(cat);
}

这样一改,以前的功能又不能用了(为啥不能列出保管的宠物了?)

从以上需求场景可以看到:

1、对于不确定或者不关心实际要操作的类型,可以使用无界通配符(尖括号里一个问号,即 <?>),表示可以持有任何类型;

2、<? extends T>称之为「上界通配符」,表示只允许T及T的子类调用,例如只允许宠物类Pets的子类Cat和Dog调用;

3、<? super T>刚好相反,称之为「下界通配符」,表示只允许T及T的父类调用,例如只允许Cat的父类Felidae调用;

4、由于上界通配符<? extends T>中只知道T这个父类,而不知道具体的子类(所以用?代替),因此它无法实现向列表中加入新元素的功能,也就是做不到list.add()(这就是为什么满足不了给宠物分配笼子的需求);

5、而由于下界通配符<? super T>中只知道T这个子类,而不知道具体的父类(所以用?代替),因此它无法实现从列表中获取元素的功能,也就是做不到list.get()(这也是为什么满足不了列出保管的宠物)。

刚才说了那么多,稍稍有点绕。总结一下:

由于<? extends T>的只能取,不能存;而<? super T>得只能存,不能取,因此在架构设计中就有一个推荐的实践经验:

1、生产者producer一般用<? extends T>

2、消费者consumer一般用<? super T>

泛型讲到这里,如果能够全部明白,就可以真正畅快地去KTV嗨了。而泛型其他的知识点,像什么无界通配符、泛型参数一致性、多重限定、基类劫持接口、自限定类型、循环泛型等乱七八糟的可以统统不去管了,因为很多工程师一辈子的职业生涯中几乎都碰不到它们,除非点背到极点。还是最开始的那几个建议:

1、不钻牛角尖,有问题见招拆招

2、解决主要宏观上、业务上的问题,暂时忽略次要的技术上的、细节上的问题

3、抓大放小,用好80/20原则

KTV和泛型(3)的更多相关文章

  1. KTV和泛型(2)

    很多使用泛型的小伙伴,都会有一个疑惑:为什么有的方法返回值前带<T>.<K, V>之类的标记,而有的方法返回值前又什么都不带呢?就像这样: // 实体基类 class Enti ...

  2. java——集合、泛型、ArrayList、LinkedList、foreach循环、模拟ktv点歌系统

    集合:一系列特殊的类,这些类可以存储任意类型的对象,长度可变,集合类都在java.util包中. 但是集合记不住对象的类型,当把对象从集合中取出时这个对象的编译类型就变成了Object类型.这样在取元 ...

  3. 一起学 Java(三) 集合框架、数据结构、泛型

    一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...

  4. .NET面试题系列[8] - 泛型

    “可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用.“ - Jon Skeet .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] ...

  5. C#4.0泛型的协变,逆变深入剖析

    C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...

  6. 编写高质量代码:改善Java程序的151个建议(第7章:泛型和反射___建议106~109)

    建议106:动态代理可以使代理模式更加灵活 Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发.我们知道一个静态代理是通过主题角色(Prox ...

  7. 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  8. C#泛型详解(转)

    初步理解泛型: http://www.cnblogs.com/wilber2013/p/4291435.html 泛型中的类型约束和类型推断 http://www.cnblogs.com/wilber ...

  9. C# 泛型

    C# 泛型 1.定义泛型类 在类定义中包含尖括号语法,即可创建泛型类: class MyGenericClass<T> { //Add code } 其中T可以遵循C#命名规则的任意字符. ...

随机推荐

  1. Spring的简单使用(1)

    一:IOC(控制反转):它是由spring容器进行对象的创建和依赖注入,程序员使用时直接取出即可 正转:例如: Student stu=new Student(): stu.setname(" ...

  2. 发布 .NET MAUI / MAUI Blazor 应用 (1) - Windows

    发布用于Windows的 .NET MAUI 应用 打开 PowerShell 终端 , 命令行进入工程目录,以我的例子工程为例, cd BlazorMaui BlazorMaui 替换为你自己工程名 ...

  3. Flutter-填平菜鸟和高手之间的沟壑

    Flutter-填平菜鸟和高手之间的沟壑 准备写作中... 1.Flutter-skia-影像,Flutter skia-图形渲染层.应用渲染层2.方法通道使用示例,用于演示如何使用方法通道实现与原生 ...

  4. Apache DolphinScheduler使用规范与使用技巧分享

    本次分享来源2021年9月4日杨佳豪同学,给大家带来的分享是基于 Apache DolphinScheduler 使用规范与使用技巧分享,分享的内容主要为以下五点: " DolphinSch ...

  5. Spring 02 控制反转

    简介 IOC IOC(Inversion of Control),即控制反转. 这不是一项技术,而是一种思想. 其根本就是对象创建的控制权由使用它的对象转变为第三方的容器,即控制权的反转. DI DI ...

  6. 在vue项目中使用UEditor--plus

    1:UEditor-plus富文本编辑器如何在vue项目中使用 备注:UEditor是由百度web前端研发部开发的所见即所得的开源富文本编辑器,由于该项目不在维护:程序员自发对其进行了维护,详见 ht ...

  7. CEOI 2019 Day2 T2 魔法树 Magic Tree (LOJ#3166、CF1993B、and JOI2021 3.20 T3) (启发式合并平衡树,线段树合并)

    前言 已经是第三次遇到原题. 第一次是在 J O I 2021 S p r i n g C a m p \rm JOI2021~Spring~Camp JOI2021 Spring Camp 里遇到的 ...

  8. Html5新增内容标签

    <canvas>画布</canvas> <audio src=""></audio> <video src="&qu ...

  9. Linux系统启动报错No bootable device解决步骤

    CSDN文章地址点击此处 磁盘的 MBR 表损坏 实验环境准备工作 查看分区类型及磁盘位置信息点击此篇 首先备份虚拟机A上的 MBR 表 dd if=/dev/vda of=MBR bs=512 co ...

  10. ubuntu下安装python

    一.安装python3.6 sudo add-apt-repository ppa:jonathonf/python-3.6 如显示不能添加"'ppa:~jonathonf/ubuntu/p ...