Java泛型,数组和方法返回类型 - 协变,逆变和不变

news2024/9/29 15:20:06

首先,让我们通常理解一下子类型规则是什么。

协变vs逆变vs双变vs不变

编程语言可能有支持以下子类型规则的特性:

    协变

        允许用超类型替换子类型。

    逆变

        允许用子类型替换超类型。

    双变

        同时是协变和逆变。

    不变

        不允许上述任何替换。

让我们看看Java支持哪些子类型规则:

Java数组是协变的

Java数组支持协变替换:

Integer[] integers = new Integer[10];
Number[] numbers = integers;

但是,上面的赋值是危险的,因为它可能最终导致ArrayStoreException:

public class CovariantArraysExample {

  public static void main(String[] args) {
      Integer[] integers = new Integer[10];
      Number[] numbers = integers;
      numbers[0] = new Double(25);
  }
}

输出

Caused by: java.lang.ArrayStoreException: java.lang.Double
	at com.logicbig.example.CovariantArraysExample.main(CovariantArraysExample.java:8)
	... 6 more

Java泛型是不变的

Java泛型具有特定类型T,不支持协变或逆变替换。这是为了避免像我们在上面的数组案例中看到的那样出现ArrayStoreException的情况。

public class InvariantGenericsExample {

  public static void main(String[] args) {
      List<Integer> integers = new ArrayList<>();
      List<Number> numbers = new ArrayList<>();
      numbers = integers;
  }
}

输出

Compilation errors:
InvariantGenericsExample.java:[11,19] incompatible types: java.util.List<java.lang.Integer> cannot be converted to java.util.List<java.lang.Number>
1 error

带有通配符'?extends'的Java泛型是协变的:

public class CovariantGenericsExample {

  public static void main(String[] args) {
      List<Integer> integers = new ArrayList<>();
      integers.add(1);

      List<? extends Number> numbers = integers;
      System.out.println(numbers);
  }
}

输出

[1] 

在赋值给List<? extends Number>后,我们不能向List中添加Number的任何子类型。例如,这样的尝试将导致编译错误:

public class CovariantGenericsExample2 {

  public static void main(String[] args) {
      List<Integer> integers = new ArrayList<>();
      integers.add(1);

      List<? extends Number> numbers = integers;
      Double d = new Double(23);
      numbers.add(d);
  }
}

输出

Compilation errors:
CovariantGenericsExample2.java:[14,16] no suitable method found for add(java.lang.Double)
    method java.util.Collection.add(capture#1 of ? extends java.lang.Number) is not applicable
      (argument mismatch; java.lang.Double cannot be converted to capture#1 of ? extends java.lang.Number)
    method java.util.List.add(capture#1 of ? extends java.lang.Number) is not applicable
      (argument mismatch; java.lang.Double cannot be converted to capture#1 of ? extends java.lang.Number)
1 error 

原因是我们不能保证列表最初是为哪种类型的元素构造的。'?extends Number'表示任何扩展Number的类型,但编译器永远不知道是什么类型。我们只能向此类集合引用添加null,或者从中删除项目,但我们不能向其添加新元素。

带有通配符'?super'的Java泛型是逆变的:

Java泛型允许用'? super'通配符将超类型替换为子类型:

public class ContravariantGenericsExample {

    public static void main(String[] args) {
        List<A> aList = new ArrayList<>();
        aList.add(new A());

        List<? super B> bList = aList;
        bList.add(new B());

        System.out.println(bList);
    }

    private static class A {
    }

    private static class B extends A {
    }
}

输出

[com.logicbig.example.ContravariantGenericsExample$A@436e27a6, com.logicbig.example.ContravariantGenericsExample$B@69c3928e]

请注意,在上述情况下,我们在赋值后能够添加类型B的元素。这是因为,编译器知道bList是B的任何超类型的列表,而B(或B的子类型)肯定可以始终分配给B的超类型。

另一方面,从'? super B',编译器将永远不知道B的哪个超类型,这意味着我们不能向bList添加类型A或A的其他子类型的任何元素。

Java中的协变方法返回类型

Java允许子类覆盖可以返回更特定类型的方法。换句话说,子类方法的返回类型必须能够替换超类方法的返回类型。

方法的协变返回类型是当方法在子类或子接口中被覆盖时,可以被“更窄”的类型(子类型)替换的类型。

换句话说,被覆盖的方法可以有更具体的返回类型。只要新的返回类型可以赋值给我们正在覆盖的方法的返回类型,它就可以被使用。

Java自5.0版本以来就支持这个特性。

public class CovariantReturnExample {

    interface SuperType {
    }

    interface SubType extends SuperType {
    }

    interface A {
        SuperType getType ();
    }

    interface B extends A {
        SubType getType ();
    }
}

注意:协变返回可以在扩展类或扩展接口时使用。在上述示例中,SuperType-SubType 和/或 A-B 可以是类。

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

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

相关文章

Intellij IDEA 如何删掉插件

在 Intellij IDEA 的配置中&#xff0c;找到插件选项。 在插件选项中&#xff0c;选择需要删除的插件&#xff0c;然后在右侧的对话框中选择 uninstall 就可以了。 卸载以后&#xff0c;可能不会要求重启&#xff0c;为了安全起见&#xff0c;还是重启下你的 IDE 吧。

C++容器详解

什么是容器 首先&#xff0c;我们必须理解一下什么是容器&#xff0c;在C 中容器被定义为&#xff1a;在数据存储上&#xff0c;有一种对象类型&#xff0c;它可以持有其它对象或指向其它对像的指针&#xff0c;这种对象类型就叫做容器。很简单&#xff0c;容器就是保存其它对…

Flutter控件之文本Text封装

Flutter控件之基类Widget封装 上篇文章&#xff0c;我们简单针对Widget做了一个基类封装&#xff0c;拓展出了很多常见又易用的属性&#xff0c;比如宽高&#xff0c;内外边距等等&#xff0c;很方便的为接下来的各个基础组件的封装&#xff0c;提供极大的便利&#xff0c;在上…

虚拟机启动时出现“已启用侧通道缓解”的解决方法

系列文章目录 Hypervisor launch failed centos7配置ssh免密登陆完成&#xff0c;进行ssh登陆时出现”代理承认未能使用密钥签名“ 解决pip更新的代码 文章目录 系列文章目录 一、问题描述 二、启用了侧通道缓解的虚拟机可能会出现性能下降 &#xff08;79832&#xff0…

Linux系统vim查看文件中文乱码

Linux系统查看文件-cat中文正常显示 vim中文乱码 1、背景2、环境3、目的4、原因5、操作步骤5.1、修改vim编码配置 6、验证 1、背景 服务器部署业务过程中查看文件内容&#xff0c;使用cat 命令查看中文正常显示&#xff0c;使用vim命令查看显示中文乱码 cat 查看 vim 查看 …

陶哲轩宣布主持白宫生成式AI工作组,李飞飞、Hassabis发表演讲

来源 | 新智源 ID | AI-era 【导读】最近&#xff0c;「数学天才」陶哲轩表示&#xff0c;自己将领导白宫生成式人工智能工作组&#xff0c;就当前AI评估并收集意见。在陶哲轩看来&#xff0c;加入工作流的ChatGPT在数学专业领域中&#xff0c;并没有太多增值。 近来&#xf…

Redis主从复制、哨兵、cluster集群原理+实验

Redis 主从复制 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。 默认情况下&#xff0c;每台Redis服务…

Fluent局部坐标系(曲线坐标系)

1 概述 在某些模型中&#xff0c;利用局部坐标系可极大的方便模型设置&#xff0c;例如对弯曲的多孔板设置多孔介质属性、设置各向异性的材料属性等。 2 创建坐标系 通过树状菜单中“curvilinear coordinate system”可创建曲线型局部坐标系。 右键点击“新建”&#xff0c;在如…

Linux 安装redis

一、概述 官网&#xff1a;https://redis.io/ Redis 是完全开源免费的&#xff0c;遵守BSD协议&#xff0c;是一个高性能的key-value数据库。 Redis 与其他 key - value 缓存产品有以下三个特点&#xff1a; Redis支持数据的持久化&#xff0c;可以将内存中的数据保持在磁盘…

基于静态和动态特征融合的语音情感识别层次网络

题目Hierarchical Network based on the Fusion of Static and Dynamic Features for Speech Emotion Recognition时间2021年期刊\会议ICASSP 基于静态和动态特征融合的语音情感识别层次网络 摘要&#xff1a;许多关于自动语音情感识别&#xff08;SER&#xff09;的研究都致…

【集群划分】基于kmeans的电压调节的集群划分【IEEE33节点】

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

HTTP/HTTPS协议详解

目录 一. HTTP详解 ✅1.1 概念 ✅1.2 HTTP的协议格式 1.2.1 HTTP请求体格式&#xff1a; 1.2.2 HTTP响应体格式&#xff1a; ✅1.3 HTTP请求方法 ✅1.4 认识请求报头 ✅1.5 HTTP请求过程 ✅1.6 认识状态码 二. HTTPS详解 ✅2.1 HTTPS简介 ✅2.2 HTTPS加密过程 TCP/UDP是位于传…

d3d(Direct X)中的com技术详解

本文不会对Com进行非常详细的分析 因为这个技术分析起来难度还是非常大的 要想真正弄懂还是非常困难的 我只会针对d3d中使用到的com技术和comptr技术进行说明 所以看完本文后 可以熟练使用d3d中使用到的相应技术 comptr类似于c11中的智能指针,用于管理com对象的生命周期,所以我…

深度学习基础篇之卷积神经网络(CNN)

一、CNN的基本结构 首先我们来看CNN的解百纳结构&#xff0c;一个常见的图像识别CNN模型如下图&#xff1a; 从图中可以看出最左边的图像就是模型的输入层&#xff0c;在计算机中就是若干个矩阵&#xff0c;这点与DNN类似。 接着是卷积层&#xff08;Convolution Layer&…

rtmp协议

目录 1 rtmp格式 2 header 3 chunk data 1 rtmp格式 Real Time Messaging Protocol&#xff08;实时消息传送协议协议)是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的私有协议。 在RTMP协议中信令和媒体数据都称之为Message&#xff0c;包含Mess…

Intellij IDEA 提示 Thrift Support 支持不兼容

最近升级 Intellij IDEA 后老提示 Thrift Support 不兼容。 后来看了下这个插件已经不少时间没有更新了&#xff0c;也一直不知道这个插件是干什么 用的&#xff0c; 后来看了下&#xff0c;这个插件是&#xff1a; Thrift是一种接口描述语言和二进制通讯协议&#xff0c;它被…

【031】基于Vue的学生宿舍管理系统课设(含源码、数据库、运行教程

前排提示&#xff1a;项目源码已放在文末 基于VueSpringbootmysql员工考勤管理系统(多角色登录、请假、打卡) 开发环境&#xff1a;SpringbootMysqlVueNodejsMavenJDK1.8&#xff0b;redis 技术栈&#xff1a;spring-boot、mysql、mybatis-plus 数据库&#xff1a; 源码、…

Centos7单机部署Flink13.6及测试FinkCDC同步MySQL

一、背景 公司CDH6.3.2里面的版本是Flink1.12.0。而因为FlinkCDC2.0.0只支持Flink1.13.0以后&#xff0c;版本不匹配&#xff0c;所以只能升级版本。但是升级版本是个大工程&#xff0c;要编译、要parcel制作工具&#xff0c;而且是生产环境的升级&#xff0c;没办法因为要测试…

初识Spring MVC框架,Spring MVC工作原理

Java EE三层架构 在Java EE开发中&#xff0c;系统经典的三层架构包括表现层、业务层和持久层。三层架构中&#xff0c;每一层各司其职&#xff0c;表现层(Web层&#xff09;负责接收客户端请求&#xff0c;并向客户端响应结果;业务层( Service层&#xff09;负责业务逻辑处理…

3 手工推导Neural Networ

线性模型假设的问题 如上图&#xff0c;对非线性类边界的数据进行分类 一个解决方案是将数据映射到更高维的空间&#xff0c;就变成线性可分的了。 ϕ \phi ϕ 是一个映射函数&#xff0c;将x从一个低维空间映射到高维空间。 ϕ \phi ϕ 可不可以是一个线性函数&#xff1f; …