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

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(使用前将#替换为@)

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

  • 两个整数乘积的模

    我必须找到c c a b mod m a b c m 是 32 位整数 但 a b 可以超过 32 位 我正在尝试找出一种计算 c 的方法 而不使用 long 或任何 gt 32 位的数据类型 有任何想法吗 如果m是质数 事情可以简化吗 注
  • 为什么即使我的哈希码值相同,“==”也会返回 false

    我写了一个像这样的课程 public class HashCodeImpl public int hashCode return 1 public static void main String args TODO Auto generat
  • 什么是抽象类? [复制]

    这个问题在这里已经有答案了 当我了解抽象类时 我说 WT H 问题 创建一个无法实例化的类有什么意义呢 为什么有人想要这样的课程 什么情况下需要抽象类 如果你明白我的意思 最常见的是用作基类或接口 某些语言有单独的interface构建 有
  • Android studio - 如何保存先前活动中选择的数据

    这是我的代码片段 这Textview充当按钮并具有Onclicklistner在他们 当cpu1000时Textview单击它会导致cpu g1000其代码如下所示的类 public class Game 1000 extends AppC
  • C# Byte[] 转 BCD 和 BCD 转 INT

    我有一个由 CashRegister Machine 创建的 Hex 文件 我必须读入这个文件 文件使用下面详述的格式 它就像套接字数据包 代码数据 2字节PLU 代码数据 7 字节单价数据 5字节数量数据 5字节数据总量 5字节PLU 名
  • 从 MATLAB 调用 Java?

    我想要Matlab程序调用java文件 最好有一个例子 需要考虑三种情况 Java 内置库 也就是说 任何描述的here http docs oracle com javase 6 docs api 这些项目可以直接调用 例如 map ja
  • Mockito 使用 @Mock 时将 Null 值注入到 Spring bean 中?

    由于我是 Spring Test MVC 的新手 我不明白这个问题 我从以下代码中获取了http markchensblog blogspot in search label Spring http markchensblog blogsp
  • 如何使用 Retrofit 解析嵌套 json....?

    我不知道该怎么办使用 Retrofit 解析 json 熟悉使用 Retrofit 解析简单的 json 但不熟悉解析嵌套Json using Retrofit 这是我的 Json 数据 current observation image
  • 如何在 Spring 中使 @PropertyResource 优先于任何其他 application.properties ?

    我正在尝试在类路径之外添加外部配置属性资源 它应该覆盖任何现有的属性 但以下方法不起作用 SpringBootApplication PropertySource d app properties public class MyClass
  • 如何在字段值无效的情况下更改 Struts2 验证错误消息?

    我在 Web 表单上使用 Struts2 验证 如果字段假设为整数或日期 则
  • 在 C# 中按元素相乘数组具有意想不到的性能

    我想找到按元素相乘两个数组的最佳方法 这是更广泛项目的一部分 其中性能而不是唯一的考虑因素 我今天开始用 C Linqpad 编写一些函数 因此它还没有以任何方式进行优化 下面代码的输出如下 Environment ProcessorCou
  • Akka 与现有 java 项目集成的示例

    如果我已经有现有的javaWeb 应用程序使用spring and servlet容器 将 Akka 集成到其中的正确方法是什么 就像我将会有Actor1 and Actor2互相沟通的 开始使用这些演员的切入点是什么 例如 1 把它放在那
  • Java继承,扩展类如何影响实际类

    我正在查看 Sun 认证学习指南 其中有一段描述了最终修饰符 它说 如果程序员可以自由地扩展我们所知的 String 类文明 它可能会崩溃 他什么意思 如果可以扩展 String 类 我是否不会有一个名为 MyString 的类继承所有 S
  • 如何从文本文件读取整数到数组

    这就是我想做的 我对此有些不满 但我希望你能容忍我 这对我来说是一个非常新的概念 1 在我的程序中 我希望创建一个包含 50 个整数的数组来保存来自文件的数据 我的程序必须获取用户的文档文件夹的路径 2 文件的名称为 grades txt
  • 使用 HtmlUnit 定位弹出窗口

    我正在构建一个登录网站并抓取一些数据的程序 登录表单是一个弹出窗口 所以我需要访问这个www betexplorer com网站 在页面的右上角有一个登录链接 写着 登录 我单击该链接 然后出现登录弹出表单 我能够找到顶部的登录链接 但找不
  • 将 JScrollPane 添加到 JFrame

    我有一个关于向 Java 框架添加组件的问题 我有一个带有两个按钮的 JPanel 和一个添加了 JTable 的 JScrollPane 我想将这两个添加到 JFrame 中 我可以将 JPanel 添加到 JFrame 或将 JScro
  • 手动设置Android Studio的JDK路径

    如何为 Android Studio 使用自定义 JDK 路径 我不想弄乱 PATH 因为我没有管理员权限 是否有某个配置设置文件允许我进行设置 如果您查看项目设置 您可以从那里访问 jdk 在标准 Windows 键盘映射上 您可以在项目
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似
  • 由 Servlet 容器提供服务的 WebSocket

    上周我研究了 WebSockets 并对如何使用 Java Servlet API 实现服务器端进行了一些思考 我没有花费太多时间 但在使用 Tomcat 进行一些测试时遇到了以下问题 如果不修补容器或至少对 HttpServletResp
  • Spring RESTful控制器方法改进建议

    我是 Spring REST 和 Hibernate 的新手 也就是说 我尝试组合一个企业级控制器方法 我计划将其用作未来开发的模式 您认为可以通过哪些方法来改进 我确信有很多 RequestMapping value user metho

随机推荐

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

    我有一些函数可以根据一组输入数据尝试各种方法来解决问题 如果该方法无法解决问题 则该函数将抛出异常 我需要按顺序尝试它们 直到没有抛出异常为止 我正在尝试找到一种方法来优雅地做到这一点 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 的子类型 数组是协变的 因为字符串是对象