Java泛型之通配符类型

news2024/9/20 13:03:45

1. 案例分析

class Animal {
    @Override
    public String toString() {
        return "animal";
    }
}

class Cat extends Animal {
    @Override
    public String toString() {
        return "cat";
    }
}

class Dog extends Animal {
    @Override
    public String toString() {
        return "dog";
    }
}

public class App {
    public static void show(ArrayList<Animal> animals) {
        for(Animal a : animals) {
            System.out.println(a);
        }
    }

    public static void main(String[] args) {
        ArrayList<Cat> list = new ArrayList<Cat>();
        list.add(new Cat());
        show(list);
        list.get(0).getCat();
    }
}

在main方法中, 构造了一个ArrayList类的对象, 调用show方法打印该对象中的元素。 一切看起来都很正常, 结果在编译时, 编译器报错如下:

在这里插入图片描述
[分析]:
    Cat是Animal的子类, ArrayList<Cat>理应是ArrayList<Animal>的子类了, 为何还提示“不兼容的类型”? 其实这只不过是我们想当然而已,假如ArrayList<Cat>可以转型为ArrayList<Animal>, 那么利用后者就可以添加任何派生于Animal的对象了, 如Dog类的对象, 这就失去了ArrayList<Cat>原本的目的了, 因此编译器才会给我们报告错误。
    那么ArrayList<Cat>ArrayList<Dog>, 甚至ArrayList<String>, 它们有没有公共的父类型呢? 答案是有, 那就是ArrayList<?>"?" 是通配符, 代表任意类型。

好,修改代码,将show()中的参数修改为ArrayList<?>类型。
同时注意,在show()中,由于元素类型是未知的,所以不能用for(Animal a : animals)来循环,但是所有的对象类型都是Object的子类,所以可以使用Object来替代,否则报错(不兼容的类型, capture#1, 共 ?无法转换为Animal)。

public static void show(ArrayList<?> animals) {
        for(Object a : animals) {
            System.out.println(a);
        }
    }

此时编译,一切正常运行。

[注意]:
    再来关注一下 void show(ArrayList<?> animals) 函数,由于使用了通配符类型, 因此不能往animals中写入任何对象, 毕竟元素的类型是未知的, 如果允许你写入, 那岂不是可以写入任意类型的对象了? 显然, 这是不允许的。 同时也不能调用animals中存储的对象的方法(从Object类继承的方法除外) , 因为类型都不确定, 又怎么能知道这些方法有没有呢? 例如下面的代码在编译期间就会报错。

public static void show(ArrayList<?> animals) {
        animals.add(new Dog());		// error
        animals.get(0).showCat();	// error
        // ... 
}

在这里插入图片描述


2. 通配符的子类型限定(<? extends T>)

    "?"这种通配符貌似功能很强大, 可以匹配任何类型, 但实际上,你会发现什么都做不了。 其实, 我们可以对通配符做限定, 来缩小通配符匹配的范围。 例如, 对于上面的例子, 我们希望是任何Animal类的子类型, 而不是所有类型, 于是可以用通配符: ? extends Animal来表示。 要注意的是, 这里的extends和类继承的extends并不是一个含义, 前者只是表示Animal或者任何Animal的子类型, extends后的类型也可以是接口类型。
    对通配符进行限定后就比较明确了, ArrayList<? extends Animal>ArrayList<Cat>ArrayList<Dog>的父类型, 而不是ArrayList<String>ArrayList<Double>...的父类型。

abstract class Shape {
    public abstract void draw(Canvas c);
}

class Circle extends Shape {
    private int num;

    public Circle(int num) {
        this.num = num;
    }

    @Override
    public void draw(Canvas c) {
        System.out.println("draw circle " + this.num + ".");
    }
}

class Rectangle extends Shape {
    private int num;

    public Rectangle(int num) {
        this.num = num;
    }

    @Override
    public void draw(Canvas c) {
        System.out.println("draw rectangle " + this.num + ".");
    }
}

class Canvas {
    public void drawAll(ArrayList<? extends Shape> list) {
        for(Shape shape : list) {
            shape.draw(this);
        }
    }
}

public class App {

    public static void main(String[] args) {
        ArrayList<Circle> circleList = new ArrayList<Circle>();
        circleList.add(new Circle(111));
        circleList.add(new Circle(222));

        ArrayList<Rectangle> rectList = new ArrayList<Rectangle>();
        rectList.add(new Rectangle(333));
        rectList.add(new Rectangle(444));

        Canvas can = new Canvas();
        can.drawAll(circleList);
        can.drawAll(rectList);
    }
}

3. 通配符的超类型限定(<? super T>)

未完待续。。。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023/4/25

今天主要重新复习了一下树的基础知识&#xff0c;对于树的遍历和深度的求解进行了一些训练&#xff08;复习了一下写过的题&#xff09; 刷了两个关于树的简单题 104. 二叉树的最大深度 难度简单1586收藏分享切换为英文接收动态反馈 给定一个二叉树&#xff0c;找出其最大深度…

mysql的读提交与可重复读

前景介绍 隔离级别脏读可能性不可重复读可能性幻读可能性加读锁READ UNCOMMITTEDYESYESYESNOREAD COMMITTEDNOYESYESNOREPEATABLE READNONOYESNOSERALIZABLENONONONO mysql事务 READ COMMITTED 时间事务1事务2事务3T1beginbeginbeginT2update wx_va set value “TT1” wher…

数据库基础篇 《13.约束》

1. 约束(constraint)概述 1.1 为什么需要约束 数据完整性&#xff08;Data Integrity&#xff09;是指数据的精确性&#xff08;Accuracy&#xff09;和可靠性&#xff08;Reliability&#xff09;。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成…

Windows10下安装Ubuntu22.04(打造双系统)步骤 + 安装Nvidia显卡驱动

文章目录 下载Ubuntu22.04制作Ubuntu安装盘对硬盘分区查看磁盘分区形式 安装Ubuntu关于无法定位软件包错误安装显卡驱动 训练神经网络常用Lunix系统&#xff0c;这里使用Ubuntu22.04。 记录一下Windows10Ubuntu双系统安装方法。 下载Ubuntu22.04 下载链接&#xff1a;Ubuntu …

【Linux】一文读懂HTTP协议:从原理到应用

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;HTTP协议…

如何提高项目估算精准度 关键有3方面

软件规模可以用多种方式进行估算&#xff0c;但是用功能点估算方式更准确&#xff0c;而自动估算让估算更快速&#xff0c;我们以CoCode需求分析工具为例来说明&#xff0c;如何提高项目估算精准度&#xff1f; 一、调整功能点数 要提高项目估算精准度&#xff0c;首先应该提高…

Pytorch 入门资源(一) annaconda3下安装pytorch2.0.0和python3.11,使用Pycharm编辑器环境配置

一、环境安装 用annaconda3-2023.03-windows_x86_64&#xff0c;安装上python3.11和pytorch2.0.0环境。 下载pycharm community版本&#xff0c;将pycharm环境选择到pytorch&#xff0c;就可以开始上手Pytorch了。 指路几个安装博客&#xff1a; 【ok】Anaconda3的安装配置…

springcloud的项目使用一个tomcat部署

背景 我们项目使用springcloud、redis&#xff08;缓存&#xff09;、rocketMQ&#xff08;消息中间件&#xff09;、tinyid&#xff08;分布式id&#xff09;、minio&#xff08;文件存储&#xff09;、nacos&#xff08;配置注册中心&#xff09;这些组件开发了一个mes系统&…

YOLOv7+单目实现三维跟踪(python)

YOLOv7单目跟踪 1. 目标跟踪2. 测距模块2.1 设置测距模块2.2 添加测距 3. 主代码4. 实验效果 相关链接 1. YOLOv5单目测距&#xff08;python&#xff09; 2. YOLOv7单目测距&#xff08;python&#xff09; 3. YOLOv5单目跟踪&#xff08;python&#xff09; 4. 具体效果已在B…

中期国际:值得信赖的外汇MT4开户平台应该具备那些特点

在外汇市场中&#xff0c;有许多外汇平台供投资者选择。然而&#xff0c;由于市场存在许多复杂因素&#xff0c;选择平台时必须谨慎。投资者必须选择具有可靠资质的正规外汇MT4开户平台&#xff0c;以提高投资的安全性。选择外汇MT4开户平台非常重要&#xff0c;因此&#xff0…

LVS负载均衡群集—NAT

目录 一、群集的概述1、群集的含义2、出现高并发的解决方法3、群集的三种分类3.1负载均衡群集3.2高可用群集3.3高性能运算群集 4、负载均衡的结构 三、LVS调度器用的调度方法四、LVS的工作模式及其工作过程1.NAT模式&#xff08;VS-NAT&#xff09;2.直接路由模式&#xff08;V…

springboot整合juit和springboot整合mybatis

springboot整合juit 先看一眼包路径&#xff0c;发现main程序的路径和测试类的路径是一样的 启用新注解&#xff1a;SpringBootTest代替了之前sm整合juit时的 RunWith(SpringJUnit4ClassRunner.class) //spring配置类 ContextConfiguration(classes config.class)新的如此…

protoc 插件-protoc-gen-grpc-gateway-gosdk

&#x1f447;我在这儿 基本介绍 protoc-gen-grpc-gateway-gosdk 是一个 protoc 插件, 能根据 proto 文件一键生成 go http sdk 客户端代码&#xff0c;通过借助 grpc-gateway 插件将 grpc 接口转化为 http 的方式, 进而可以通过本插件生成 http sdk 代码。 特性 1.一键自动生…

springboot整合cache+redis

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、cache是什么&#xff1f;二、使用步骤1.使用方式1.引入依赖2.搭建项目依赖问题application.ymlTestControllerTestServiceTestServiceImplUserMapperMyRedi…

使用vue.component全局注册组件、props的使用

通过components注册的是私有子组件 例如&#xff1a; 在组件A的 components 节点下&#xff0c;注册了组件F。 则组件F只能用在组件A中;不能被用在组件C中。 注册全局组件 在vue项目的 main.js 入口文件中&#xff0c;通过 Vue.component() 方法&#xff0c;可以注册全局组件…

数据结构和算法学习记录——平衡二叉树(基本介绍、平衡因子、平衡二叉树的定义、平衡二叉树的高度)

目录 基本介绍 平衡因子 平衡二叉树 平衡二叉树的高度 基本介绍 什么是平衡二叉树&#xff1f; 以一个例子来解释一下&#xff1a; 搜索树结点按不同的插入次序&#xff0c;将会导致不同的深度和平均查找长度ASL 在二叉搜索树中查找一个元素&#xff1a; &#xff08…

TCP 协议的低效实现

包括 Linux kernel 在内的各种 TCP 实现均使用类似 skb 的对象管理一个个 packet&#xff0c;使 TCP 失去了 “流” 特征。应用通过 syscall 每写入一批数据&#xff0c;协议栈都可能生成一个 skb&#xff1a; ​ 仅管理这些 skb 就是一笔大开销。除了 skb 数据结构本身的 cru…

Python小姿势 - import requests

import requests Python中使用requests模块发送POST请求 在使用Python进行开发时&#xff0c;经常会遇到需要向某个网址发送POST请求的情况。这时候就需要使用到requests模块了。 requests模块是Python的一个标准模块&#xff0c;可以直接使用pip安装。 安装完成后&#xff0c;…

Java每日一练(20230425)

目录 1. 乘积最大子数组 &#x1f31f;&#x1f31f; 2. 插入区间 &#x1f31f;&#x1f31f; 3. 删除有序数组中的重复项 II &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏…

CesiumForUnreal之3DTileset点选拾取属性与单体高亮

文章目录 1.实现目标2.实现过程2.1 3DTiles数据准备2.2 属性拾取2.3 单体高亮3.参考资料1.实现目标 在UE5中使用CesiumForUnreal插件加载本地的3dTiles建筑白模数据,实现点击拾取3DTileset单体要素的属性数据,并对高亮单体进行展示,GIF动图如下: 2.实现过程 总体的实现过程…