为什么数组是协变的,而泛型是不变的?

2024-03-15

来自 Joshua Bloch 的《Effective Java》,

  1. 数组与泛型类型有两个重要的不同之处。第一个数组是协变的。泛型是不变的。
  2. 协变仅仅意味着如果 X 是 Y 的子类型,那么 X[] 也将是 Y[] 的子类型。数组是协变的,因为字符串是对象的子类型,所以

    String[] is subtype of Object[]

    不变只是意味着无论 X 是否是 Y 的子类型,

     List<X> will not be subType of List<Y>.
    

我的问题是为什么决定在 Java 中使数组协变?还有其他 SO 帖子,例如为什么数组是不变的,而列表是协变的? https://stackoverflow.com/questions/6684493/why-are-arrays-invariant-but-lists-covariant,但他们似乎专注于 Scala,而我无法跟上。


Via 维基百科 http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Covariant_arrays_in_Java_and_C.23:

Java 和 C# 的早期版本不包含泛型(又名参数多态性)。

在这种情况下,使数组不变会排除有用的多态程序。 例如,考虑编写一个函数来打乱数组,或者编写一个使用以下函数测试两个数组是否相等的函数Object.equals元素上的方法。该实现不依赖于数组中存储的元素的确切类型,因此应该可以编写一个适用于所有类型数组的函数。很容易实现类型的功能

boolean equalArrays (Object[] a1, Object[] a2);
void shuffleArray(Object[] a);

但是,如果数组类型被视为不变,则只能在类型完全相同的数组上调用这些函数Object[]。例如,人们无法对一组字符串进行打乱。

因此,Java 和 C# 都以协变方式对待数组类型。例如,在 C# 中string[]是一个子类型object[],而在 Java 中String[]是一个子类型Object[].

这回答了“为什么数组是协变的?”这个问题,或者更准确地说,“为什么were数组变得协变当时?"

当引入泛型时,由于中指出的原因,它们故意不成为协变的乔恩·斯基特的回答 https://stackoverflow.com/a/2745301/697449:

No, a List<Dog>不是一个List<Animal>。考虑一下你可以用List<Animal>- 您可以添加任何动物......包括猫。现在,你能合乎逻辑地将一只猫添加到一窝小狗中吗?绝对不。

// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new List<Dog>();
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?

突然你有一个very困惑的猫。

维基百科文章中描述的使数组协变的最初动机并不适用于泛型,因为通配符 http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html使协方差(和逆变)的表达成为可能,例如:

boolean equalLists(List<?> l1, List<?> l2);
void shuffleList(List<?> l);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么数组是协变的,而泛型是不变的? 的相关文章

  • Java:迭代 Collection 的最佳方法(此处为 ArrayList)

    今天 当我看到一段我已经使用了数百次的代码时 我很高兴地开始编码 迭代集合 此处为 ArrayList 出于某种原因 我实际上查看了 Eclipse 的自动完成选项 这让我想知道 在什么情况下以下循环比其他循环更好使用 经典的数组索引循环
  • org.apache.sling.api.resource,version=[2.3,3) -- 无法解析

    您好 我无法访问我的项目内容 我已经上传了从 CQ 访问内容所需的所有包 我唯一能看到的是 org apache sling api resource version 2 3 3 无法解析 这是否是异常的原因 如果是 请告诉我如何解决 中Q
  • java中如何连接字符串

    这是我的字符串连接代码 StringSecret java public class StringSecret public static void main String args String s new String abc s co
  • 我需要什么库才能在 Java 中访问这个 com.sun.image.codec.jpeg?

    我正在用java创建一个图像水印程序 并导入了以下内容 import com sun image codec jpeg JPEGCodec import com sun image codec jpeg JPEGEncodeParam im
  • Java 文件上传速度非常慢

    我构建了一个小型服务 它从 Android 设备接收图像并将其保存到 Amazon S3 存储桶中 代码非常简单 但是速度非常慢 事情是这样的 public synchronized static Response postCommentP
  • 如何模拟从抽象类继承的受保护子类方法?

    如何使用 Mockito 或 PowerMock 模拟由子类实现但从抽象超类继承的受保护方法 换句话说 我想在模拟 doSomethingElse 的同时测试 doSomething 方法 抽象超类 public abstract clas
  • 将 SignedHash 插入 PDF 中以进行外部签名过程 -workingSample

    遵循电子书第 4 3 3 节 PDF 文档的数字签名 https jira nuxeo com secure attachment 49931 digitalsignatures20130304 pdf 我正在尝试创建一个工作示例 其中 客
  • 如何在 Java 中测试一个类是否正确实现了 Serialized(不仅仅是 Serialized 的实例)

    我正在实现一个可序列化的类 因此它是一个与 RMI 一起使用的值对象 但我需要测试一下 有没有办法轻松做到这一点 澄清 我正在实现该类 因此在类定义中添加 Serialized 很简单 我需要手动序列化 反序列化它以查看它是否有效 我找到了
  • 编辑文件名在 JComboBox 中的显示方式,同时保持对文件的访问

    我对 Java 很陌生 对堆栈溢出也很陌生 我正在尝试利用 JMF API 创建一个用 Java 编码的简单媒体播放器 到目前为止 我已经能够设置一个简单的队列 播放列表来使用JComboBox called playListHolder
  • Javafx过滤表视图

    我正在尝试使用文本字段来过滤表视图 我想要一个文本字段 txtSearch 来搜索 nhs 号码 名字 姓氏 和 分类类别 我尝试过在线实施各种解决方案 但没有运气 我对这一切仍然很陌生 所以如果问得不好 我深表歉意 任何帮助将不胜感激 我
  • 有没有一种快速方法可以从 Jar/war 中删除文件,而无需提取 jar 并重新创建它?

    所以我需要从 jar war 文件中删除一个文件 我希望有类似 jar d myjar jar file I donot need txt 的内容 但现在我能看到从 Linux 命令行执行此操作的唯一方法 不使用 WinRAR Winzip
  • 如何在JSTL中调​​用java方法? [复制]

    这个问题在这里已经有答案了 这可能是重复的问题 我只想调用不是 getter 或 setter 方法的方法例如 xyz 类的 makeCall someObj stringvalue Java类 Class XYZ public Strin
  • 游戏内的java.awt.Robot?

    我正在尝试使用下面的代码来模拟击键 当我打开记事本时 它工作正常 但当我打开我想使用它的游戏时 它没有执行任何操作 所以按键似乎不起作用 我尝试模拟鼠标移动和点击 这些动作确实有效 有谁知道如何解决这个问题 我发现这个问题 如何在游戏中使用
  • 替换后增量

    我自己已经有一个问题了 但我想扩展它后增量示例 https stackoverflow com questions 51308967 post increment with example char a D int b 5 System o
  • Eclipse 中 Spring MVC 模型对象的 (jsp /jstl) 视图中的代码辅助

    在 Spring MVC 中 当将对象放置在视图模型中时 如下所示 public String getUser Model model fetch user model addAttribute user user return viewN
  • 具有特定参数的 Spring AOP 切入点

    我需要创建一个我觉得很难描述的方面 所以让我指出一下想法 com x y 包 或任何子包 中的任何方法 一个方法参数是接口 javax portlet PortletRequest 的实现 该方法中可能有更多参数 它们可以是任何顺序 我需要
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • hashcode 的默认实现为以相同方式构造的对象返回不同的值

    我在这里编写一个示例代码 public class Test private int i private int j public Test TODO Auto generated constructor stub public Test
  • ServletContainer 类未找到异常

    我无法再编译我的球衣项目 并且出现以下异常 GRAVE Servlet Project API threw load exception java lang ClassNotFoundException com sun jersey spi
  • GUI Java 程序 - 绘图程序

    我一直试图找出我的代码有什么问题 这个想法是创建一个小的 Paint 程序并具有红色 绿色 蓝色和透明按钮 我拥有我能想到的让它工作的一切 但无法弄清楚代码有什么问题 该程序打开 然后立即关闭 import java awt import

随机推荐

  • 尝试不同的函数,直到不抛出异常

    我有一些函数可以根据一组输入数据尝试各种方法来解决问题 如果该方法无法解决问题 则该函数将抛出异常 我需要按顺序尝试它们 直到没有抛出异常为止 我正在尝试找到一种方法来优雅地做到这一点 try answer method1 x y z ex
  • Google Data API - 两条腿的身份验证令牌重用

    我正在为 Google Contact Data API 使用两条腿的 OAuth 并在每个请求上生成令牌 是否可取或者我应该存储令牌以便下次重复使用吗 另外 如何检测陈旧的令牌 我正在使用Python 和 Gdata Python 客户端
  • JDBCPreparedStatement 始终返回 1 作为自动生成的键[重复]

    这个问题在这里已经有答案了 我有这段代码试图在数据库中插入一条记录 try Connection conn getConnection String sql INSERT INTO myTable userId content timest
  • BotFramework:“状态大小超出了配置的限制。”

    我正在开发一个机器人 每当我在表单流中 PostAsync 英雄卡 50 张英雄卡 时 最后它都会给我一条错误消息 状态大小超出了配置的限制 来自 Microsoft Bot Connector DLL 尝试 setPrivateConve
  • CSS 规则“.drop.a”应用于类“drag a”

    我有以下 HTML 标记 div class drag a div div class drop a div 我还有以下 CSS 规则 该规则仅适用于我的第二个 div drop a background color red 这工作正常 除
  • 截断存储过程中的表

    当我在 Oracle shell 中运行以下命令时 它工作正常 truncate table table name 但是当我尝试将其放入存储过程时 CREATE OR REPLACE PROCEDURE test IS BEGIN trun
  • Cypress 与 NextJS SSR - 使用 Axios 拦截 RESTful API

    我正在尝试在我的 SSR next js 应用程序上使用 cypress 和固定装置编写一些测试 该应用程序使用 Axios 连接到 RESTful API 但我在拦截 RESTful API 时遇到了麻烦cy intercept 因为 c
  • JavaScript 中的文件切片会导致空 blob

    我正在实现一个基于浏览器的分块文件上传器 打开我正在使用的文件
  • Git 重置所有具有特定扩展名的文件

    我对多种类型的文件进行了更改 例如 tsx scss and scss d ts 并已提交并推送到我的分支 有什么办法可以只重置扩展名 scss d ts与主人 保留更改 tsx and scss仅重置 scss d ts与主人 Thank
  • 停止 Thrift 服务器(TSimpleServer)

    我有一个 Thrift 服务器的简单用例 TSimpleServer 其中我生成了几个线程 除了主线程之外 新生成的线程之一进入 Thrift 事件循环 即server serve 在主线程中收到信号后 我调用server stop 这导致
  • 需要将我的基于 HTML5 的 Web 应用程序转换为面向所有移动设备的移动应用程序

    是否可以将我现有的 HTML jquery js 网站转换为针对所有设备 iPhone Android 黑莓等 的移动应用程序 以下是我能想到的几点 如果我错了 请纠正我 添加 jquerymobile js 并更改 css 样式 基于访问
  • 让控制器发回不带 Content-Type 标头的响应

    我在控制器内设置了一个 Rails 3 代理方法 以使用 Nginx 的 X Accel Redirect 在允许用户的情况下从远程服务器传递特定的 URI 不幸的是 Rails 总是发送某种 Content Type 标头 该标头优先于从
  • 自动替换wpf RichTextBox中的文本

    我有一个 WPF NET 4 C RichTextBox我想用其他字符替换该文本框中的某些字符 这将发生在KeyUp event 我想要实现的目标是将首字母缩略词替换为完整单词 例如 pc 个人电脑sc 星际争霸 etc 我查看了一些类似的
  • 转义注释标签内的 html

    转义 html 没问题 它会删除 lt s and gt s etc 我遇到了一个问题 我在注释标签内输出文件名 例如 当然 如果你不逃避 事情可能会很糟糕 所以它变成了 问题是 如果文件名称中包含 则所有 html 都会被搞砸 因为不允许
  • didMove(查看: SKView) 和 didMoveToView(查看: SKView) 有什么区别?

    如标题所示 didMove to view SKView 和 didMoveToView view SKView 有什么区别 我知道 didMoveToView 是方法 并且该视图在旧 版本中属于 SKView 类型 我不明白将 查看 SK
  • iPad iPhone 规模背景图片

    只是想知道是否有其他人经历过 iPad iPhone 缩小背景图像以适应视口的情况 就我而言 我通过 JavaScript 交换背景图像 新的背景图像超宽 适合大型显示器 然而 iPad 正在缩小通过 javascript 添加到 DOM
  • 使用 CSS 剪辑/裁剪背景图像

    我有这个 HTML div lorem ipsum div 使用这个CSS graphic background image url image jpg width 200px height 100px 我应用的背景图像是 200x100
  • 有没有办法在flutter中从iOS中排除包?

    我正在使用仅适用于 Android 的 sms maintained 包 然而 该项目需要一个iOS版本 我目前正在做的是在开发iOS时删除该包 如何将包保留在 pubspec yaml 文件中 但禁止 iOS 检入该包 目标是拥有统一的代
  • PHP 中的 \x00 、 \x04 是什么意思

    我有一些代码有 x00 and x04 十六进制代码 这是什么意思 str implode x00 var message line 1 id var message x04 id line 2 将会发生什么线路 1 和线路 2我想将这些写
  • 为什么数组是协变的,而泛型是不变的?

    来自 Joshua Bloch 的 Effective Java 数组与泛型类型有两个重要的不同之处 第一个数组是协变的 泛型是不变的 协变仅仅意味着如果 X 是 Y 的子类型 那么 X 也将是 Y 的子类型 数组是协变的 因为字符串是对象