具有相同擦除的两种方法不需要覆盖等效(或者它们的签名不是它们之间的子签名)?

2024-03-09

我正在阅读关于 jdk6 的令人难以置信的书“java scjp 认证程序员指南”,其中有一个关于泛型覆盖的部分。它描述了子签名和覆盖等效项,并描述了我引用的一些覆盖等效项的示例:

给定类中的以下三个泛型方法声明:

static <T> void merge (MyStack<T> s1, MyStack<T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? extends T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? super T> s2) { /*...*/ }

擦除后,这三个方法的签名为:merge(MyStack, MyStack)即,方法的签名是重写等效的,因此这些方法 没有超载。

我不完全同意这些方法是覆盖等效的,事实上,我认为这些方法有“删除的名称冲突”,但没有一个是另一个方法的子签名......可能我错了,所以我想对此有所了解。

签名的定义让我认为它们不是它们之间的签名。

在 JSL 6 #8.4.2 方法签名中(http://docs.oracle.com/javase/specs/jls/se6/html/classes.html#8.4.2 http://docs.oracle.com/javase/specs/jls/se6/html/classes.html#8.4.2)

如果两个方法具有相同的名称和参数类型,则它们具有相同的签名。 如果满足以下所有条件,则两个方法或构造函数声明 M 和 N 具有相同的参数类型:

  • 他们。具有相同数量的形式参数(可能为零)

  • 它们具有相同数量的类型参数(可能为零)

  • Let <A1,...,An>是 M 的形式类型参数,令<B1,...,Bn>是 N 的形式类型参数。将 N 类型中每次出现的 Bi 重命名为 Ai 后,相应类型变量的界限以及 M 和 N 的参数类型是相同的。

方法 m1 的签名是方法 m2 的签名的子签名,如果 m2 与 m1 具有相同的签名,或者 m1 的签名与 m2 的签名擦除相同

...

两个方法签名 m1 和 m2 是覆盖等效的,当且仅当 m1 是 m2 的子签名或 m2 是 m1 的子签名。

在 JSL 8 # 8.4.2 中。方法签名(http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2 http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2)

如果两个方法或构造函数 M 和 N 具有相同的名称、相同的类型参数(如果有)(第 8.4.4 节),并且在将 N 的形式参数类型调整为类型参数之后,则它们具有相同的签名M,形参类型相同。

方法 m1 的签名是方法 m2 签名的子签名,如果:

  • m2 与 m1 具有相同的签名,或者

  • m1的签名与m2的签名擦除相同。

两个方法签名 m1 和 m2 是覆盖等效的,当且仅当 m1 是 m2 的子签名或 m2 是 m1 的子签名。

EDIT 1

简而言之,我的疑问是,从关于删除的签名定义中,我明白 “一个没有删除的签名等于另一个签名的删除”..而不是 “擦除后的两个签名是相等的”..它微妙但很重要 (顺便说一句,覆盖等效定义基于子签名定义,这就是我询问子签名的原因)


TL;DR

在我看来,这本书的措辞在这里并没有很好地结合在一起。重载是根据覆盖等价性的否定来定义的,根据金龙生 (8.4.9) http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.9(释义:如果存在两个同名的方法,但不等效重写,那么它们就会重载)。

但给出的例子是方法是NOT覆盖等效,但是DO由于其他原因导致编译时错误(名称冲突 - 中指定的特定编译时错误JLS 8.4.8.3 http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.3),因此不要超载。


Preamble

据我了解,您提出的问题是关于这句话的确切语义的:

“...或者m1的签名与m2签名的擦除相同”

结合

m1 和 m2 是覆盖等效的,当且仅当 m1 是 m2 的子签名或 m2 是 m1 的子签名。


你的书暗示这应该解释为

"or the 的擦除m1的签名与m2签名的擦除相同"

(添加的单词以粗体斜体显示)。

而你会把它解释为

“或 m1 的签名(无需擦除) 与m2签名的擦除相同"

你的解释是正确的。我不认为这句话有歧义,因此我认为用第一种方式解释它(即erasure两个签名相同)是不正确的。你可能会喜欢看看这个相关的答案 https://stackoverflow.com/a/21690951/838992在这里增加我的观点的分量(我发现它是因为我也想检查我的理解)。


回答(不过……)

您引用的书中的部分实际上是在尝试描述超载。

现在 - 当考虑超载时 -JLS(8.4.9)说 http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.9 that:

如果一个类的两个方法(无论是在同一个类中声明,还是都由一个类继承,或者一个声明一个继承)具有相同的名称,但签名不是重写等效的,则该方法名称被称为超载。

至少从 Java 6 开始,这一点是一致的。这就是两者之间的联系所在override-equivalent和超载源于。

好的 - 所以你的方法会重载,因为它们不是严格覆盖等价的。正确的?

Wrong.

因为就在该部分的上方在 8.4.8.3 中,JLS http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.8.3放入特定的编译时错误:

如果类型声明 T 具有成员方法 m1 并且存在 T 中声明的方法 m2 或 T 的超类型,并且满足以下所有条件,则会出现编译时错误:

  • m1 和 m2 具有相同的名称。

  • m2 可从 T 访问。

  • m1 的签名不是 m2 签名的子签名(第 8.4.2 节)。

  • m1 或 m1 重写(直接或间接)的某些方法的签名与 m2 或 m2 重写(直接或间接)的某些方法的签名具有相同的擦除。

这就是您的示例中的场景。就在该部分的下方,它阐明了为什么有必要:

这些限制是必要的,因为泛型是通过擦除来实现的。上面的规则意味着在同一个类中声明的具有相同名称的方法必须具有不同的擦除。它还意味着类型声明不能实现或扩展同一泛型接口的两个不同调用。

边注

书中的示例很奇怪,因为 Java 不允许重写静态方法(而子类中方法的签名可能会在超类中隐藏该方法)。在我看来,这使得不覆盖等效的概念对于学习者来说有点棘手。但是,您可以删除static并且仍然可以看到他们试图展示的效果。

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

具有相同擦除的两种方法不需要覆盖等效(或者它们的签名不是它们之间的子签名)? 的相关文章

随机推荐

  • VS2012 发布网站 dll 而不是 cs 文件

    我有一个想要发布的简单 ASP NET 项目 我右键单击该项目并按 发布网站 但这会将我的所有 cs 文件生成到所选文件夹中 之前我一直在 bin 文件夹中获取 dll 文件而不是 cs 文件 我究竟做错了什么 问题可能出在发布设置中 请检
  • Javascript:检测 OS X“自然滚动”设置

    我面临一个问题 对于我正在做的项目 我正在检测滚轮位置 并根据该位置是否导航到下一张幻灯片 然而 一个问题是 一些 Mac 用户使用 自然滚动 反转页面上的滚动 这意味着 对于这些用户 我应该使用另一个方向的滚动作为触发器 我的问题是 有没
  • 在 VB.NET 中将 ArrayList 数据绑定到 ListBox?

    我在 VB NET 工作 我有一个名为 Invoices 的 ArrayList 其中填充了 Invoice 类的对象 我想将其数据绑定到 ListBox 以便随着 ArrayList 的内容更新并更改 ListBox 的更新 我已经在 I
  • 如何使用shell脚本访问mysql数据库?

    有没有办法使用 shell 脚本访问 MySQL 数据库 想要对多个表进行一些选择和插入 如果您能提供一些示例代码 那就太好了 因为我是脚本编写新手 这个链接似乎有你想要的信息 http www cyberciti biz faq usin
  • Android SQLite 中的多线程怎么样?

    在我的应用程序中 我必须实现一些 UI 和同步服务 它在后台运行并更新数据 同步服务并不是很简单 它使用了多线程 所以 这是我的故事 当我开始开发这个应用程序时 我对sqlite一无所知 所以我只是没有在Java中使用任何线程同步 结果 我
  • Qt 我可以在构造函数中将信号/槽连接到自身吗?

    编辑 与信号 插槽 连接无关 问题是构造函数调用构造函数 可能有更好的方法来做到这一点 我有兴趣听到这些 我有从 QLabel 派生的 MyClass 我想在信号中传递更多有关派生类的数据 而不是基本信号的数据 因此 我创建了一个插槽来拦截
  • 元音计数顺序

    这不是一个家庭作业问题 而是一个考试准备问题 我应该定义一个函数syllables word 计算音节数 一句话如下 元音的最大序列是一个音节 最终e在一个单词中不是一个音节 或者它是元音序列的一部分 的 我不必处理任何特殊情况 例如最终的
  • SQL - 将每个单词的第一个字母大写

    我知道这个线程到处都存在 但是 这是一个略有不同的情况 在我公司使用的套件中 我对 SQL 的访问权限有限 无法运行具有函数等的复杂代码 我有一个 SQL 查询 将多个列上的数据编译为一列 并使用 group by 子句来消除多重性 然而
  • TSQL RIGHT 字符串函数不起作用

    我无法理解为什么正确的功能不适合我 我试图在这里容纳尽可能多的输出 如果阅读起来令人困惑 我深表歉意 DECLARE Nbr VARCHAR 27 SELECT Nbr xmz nbr FROM xml temp AS xmz SELECT
  • 要显示此页面,Firefox 必须发送将重复之前执行的任何操作(例如搜索或订单确认)的信息

    嘿 我收到了 Firefox 的确认 To display this page Firefox must send information that will repeat any action such as a search or or
  • Cargo 是否可以在不构建应用程序的情况下下载并构建依赖项?

    有没有办法告诉Cargo http doc crates io guide html安装和构建我的所有依赖项 但不尝试构建我的应用程序 我想cargo install会这样做 但实际上它也一直用于构建我的应用程序 我想要达到一个状态carg
  • 如何从 Google Assistant 接收答案作为字符串,而不是音频流

    我正在使用 Assistant SDK 中的 python 库通过 gRPC 进行语音识别 我已识别语音并以调用该方法的字符串形式返回resp result spoken request text from googlesamples as
  • 检测 Skype 是否处于“紧凑视图”或“默认视图”

    我的应用程序的运行方式由 Skype 的视图模式决定 因为我的应用程序正在寻找类窗口TConversationWindow 如果在默认视图中 它是tSkMainForm 如果在紧凑视图中 它不是tSkMainForm 这是我尝试做的 Fun
  • 尝试将 std::pair 插入 std::set

    我无法理解这段代码中的错误是什么 include
  • 我应该将哪个会话库与 CodeIgniter 一起使用?

    我最近开始使用 CI 及其 CI 会话 但我注意到 使用 CI 会话比使用基本 PHP 会话特别耗时得多 Arrays 我有一组数据 无论登录 注销如何 它都会持续存在 称为 SESSION stats 然后我以以下形式将数据存储在该数组中
  • 如何禁用 RabbitMQ 默认 tcp 监听端口 - 5672

    我已经配置了RabbitMQrabbitmq config具有新端口号的文件 即带有 SSL 的 5671 现在我想禁用默认端口 即 5672 配置文件如下 rabbit ssl listeners 5671 ssl options cac
  • C++ 相当于指定初始化器?

    最近我一直在研究一些嵌入式设备 其中我们有一些结构体和联合体需要在编译时初始化 以便我们可以将某些不需要修改的东西保留在闪存或ROM中 并节省一点闪存或 SRAM 但会牺牲一点性能 目前 该代码编译为有效的 C99 但如果没有这种调整 它也
  • Prolog 中的条件编写

    I have Prolog包含飞机时刻表的数据库 它看起来是这样的 fly id from to days 1 0 1 0 1 0 1 正如你所看到的 有 7 个值days谓词 从星期一到星期日 我想做的是每天打印 价值所在1 但将其打印为
  • Win32:Watson 博士的完整/迷你转储和我自己编写的转储之间有区别吗?

    我有一个应用程序在发布版本中偶尔会崩溃 不幸的是 看起来它在第 3 方 DLL 中崩溃了 在试图掌握它的过程中 我一直在如何操作和 Windows 如何创建故障转储的描述的海洋中游泳 我正在考虑使用这个建议的小型转储 获取启动时崩溃的进程的
  • 具有相同擦除的两种方法不需要覆盖等效(或者它们的签名不是它们之间的子签名)?

    我正在阅读关于 jdk6 的令人难以置信的书 java scjp 认证程序员指南 其中有一个关于泛型覆盖的部分 它描述了子签名和覆盖等效项 并描述了我引用的一些覆盖等效项的示例 给定类中的以下三个泛型方法声明 static