为什么Java中必须声明接口?

2023-11-21

有时,我们有多个类,它们的某些方法具有相同的签名,但与声明的 Java 接口不对应。例如,两者JTextField and JButton(其中包括其他几个javax.swing.*)有一个方法

public void addActionListener(ActionListener l)

现在,假设我希望对具有该方法的对象执行某些操作;然后,我想要一个接口(或者也许自己定义它),例如

  public interface CanAddActionListener {
      public void addActionListener(ActionListener l);
  }

这样我就可以写:

  public void myMethod(CanAddActionListener aaa, ActionListener li) {
         aaa.addActionListener(li);
         ....

但遗憾的是,我不能:

     JButton button;
     ActionListener li;
     ...
     this.myMethod((CanAddActionListener)button,li);

这种演员阵容是非法的。编译器knows that JButton is not a CanAddActionListener,因为该类尚未声明实现该接口...然而它“实际上”实现了它.

这有时会带来不便——Java本身修改了几个核心类来实现由旧方法组成的新接口(String implements CharSequence, 例如)。

我的问题是:为什么会这样?我了解声明类实现接口的实用性。但无论如何,看看我的例子,为什么编译器不能推断出该类JButton“满足”接口声明(查看其内部)并接受强制转换?是编译器效率的问题还是还有更根本的问题?

我对答案的总结:在这种情况下,Java 可以考虑一些“结构类型”(有点像鸭子类型 - 但在编译时检查)。事实并非如此。除了一些(我不清楚的)性能和实现困难之外,这里还有一个更基本的概念:在 Java 中,接口(以及一般情况下,所有事物)的声明并不意味着仅仅结构性的(拥有带有这些签名的方法)但是语义的:这些方法应该实现一些特定的行为/意图。所以,一个类结构上满足某些接口(即,它具有带有所需签名的方法)不一定满足它语义上(一个极端的例子:回想一下“标记接口”,它甚至没有方法!)。因此,Java 可以断言一个类实现了一个接口,因为(并且仅仅因为)它已被显式声明。其他语言(Go、Scala)有其他的哲学。


Java 的设计选择是让实现类明确声明它们实现的接口,这就是一种设计选择。可以肯定的是,JVM 已针对此选择进行了优化,并且实现另一个选择(例如 Scala 的结构类型)可能会now除非添加一些新的 JVM 指令,否则会产生额外的成本。

那么究竟是什么is设计选择大约是?这一切都取决于方法的语义。考虑一下:以下方法在语义上是否相同?

  • drawString 图形形状名称)
  • 抽绳手枪名称)
  • drawString 扑克牌名称)

所有三个方法都有签名draw(String)。人们可能会从参数名称或通过阅读一些文档来推断它们具有不同的语义。有什么办法让机器知道它们是不同的吗?

Java 的设计选择是要求类的开发人员明确声明方法符合预定义接口的语义:

interface GraphicalDisplay {
    ...
    void draw(String graphicalShapeName);
    ...
}

class JavascriptCanvas implements GraphicalDisplay {
    ...
    public void draw(String shape);
    ...
}

毫无疑问,draw中的方法JavascriptCanvas旨在匹配draw图形显示的方法。如果有人试图经过一个要拔出手枪的物体,机器就能检测到错误。

Go 的设计选择更加自由,允许事后定义接口。具体类不需要声明它实现的接口。相反,新纸牌游戏组件的设计者可以声明提供纸牌的对象必须具有与签名相匹配的方法draw(String)。这样做的优点是可以使用具有该方法的任何现有类,而无需更改其源代码,但缺点是该类可能会拿出手枪而不是扑克牌。

鸭子类型语言的设计选择是完全放弃形式接口并简单地匹配方法签名。任何接口(或“协议”)的概念都是纯粹惯用的,没有直接的语言支持。

这些只是许多可能的设计选择中的三个。这三者可以简单地概括如下:

Java:程序员必须明确声明他的意图,机器会检查它。假设程序员可能会犯语义错误(图形/手枪/卡片)。

Go:程序员必须至少声明其意图的一部分,但机器在检查时几乎没有什么可继续进行的。假设程序员可能会犯错误(整数/字符串),但不太可能犯语义错误(图形/手枪/卡片)。

鸭子打字:程序员不需要表达任何意图,机器也不需要检查任何内容。假设程序员不太可能犯笔误或语义错误。

解决接口和一般类型是否足以测试书写和语义错误超出了本答案的范围。完整的讨论必须考虑构建时编译器技术、自动化测试方法、运行时/热点编译以及许多其他问题。

据了解,draw(String)为了表达观点而故意夸大例子。真实的例子将涉及更丰富的类型,这将提供更多线索来消除方法的歧义。

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

为什么Java中必须声明接口? 的相关文章

  • 如何在由子控件组成的 SWT 复合材料上跟踪鼠标?

    我创建了自己的控件 我想跟踪鼠标并添加一个MouseTrackListener 很遗憾MouseEnter and MouseLeave当鼠标移动到我的合成部分 即标签和按钮 上时 也会生成事件 Mouse enter mouse ente
  • java.lang.ClassNotFoundException:javax.mail.MessagingException

    我想使用 eclipse 将电子邮件从我的 gmail 帐户发送到另一个邮件帐户 我使用 apache tomcat 7 0 34 作为我的 Web 服务器 并使用端口 8080 作为 apache 服务器 HTTP 1 1 并使用 JRE
  • eclipse行号状态行贡献项是如何实现的?

    我需要更新状态行编辑器特定的信息 我已经有了自己的实现 但我想看看 eclipse 贡献项是如何实现的 它显示状态行中的行号 列位置 谁能指点一下 哪里可以找到源代码 提前致谢 亚历克斯 G 我一直在研究它 它非常复杂 我不确定我是否了解完
  • Android:文本淡入和淡出

    我已阅读此 stackoverflow 问题和答案 并尝试实现文本淡入和淡出 Android中如何让文字淡入淡出 https stackoverflow com questions 8627211 how to make text fade
  • 如何在 JPQL 或 HQL 中进行限制查询?

    在 Hibernate 3 中 有没有办法在 HQL 中执行相当于以下 MySQL 限制的操作 select from a table order by a table column desc limit 0 20 如果可能的话 我不想使用
  • 提供节点名或服务名,或未知 Java

    最近我尝试运行我的 Java 项目 每当我运行它并将其打开到我得到的服务器地址时 Unable to determine host name java net UnknownHostException Caused by java net
  • 在 Java 中如何找出哪个对象打开了文件?

    我需要找出答案哪个对象在我的 Java 应用程序中打开了一个文件 这是为了调试 因此欢迎使用工具或实用程序 如果发现哪个对象太具体了 这class也会很有帮助 这可能很棘手 您可以从使用分析器开始 例如VisualVM http visua
  • 断言 Kafka 发送有效

    我正在使用 Spring Boot 编写一个应用程序 因此要写信给 Kafka 我这样做 Autowired private KafkaTemplate
  • Java 中如何将 char 转换为 int? [复制]

    这个问题在这里已经有答案了 我是Java编程新手 我有例如 char x 9 我需要得到撇号中的数字 即数字 9 本身 我尝试执行以下操作 char x 9 int y int x 但没有成功 那么我应该怎么做才能得到撇号中的数字呢 ASC
  • Android 无法解析日期异常

    当尝试解析发送到我的 Android 客户端的日期字符串时 我得到一个无法解析的日期 这是例外 java text ParseException 无法解析的日期 2018 09 18T00 00 00Z 位于 偏移量 19 在 java t
  • 如何在java中将日期格式从YYMMDD更改为YYYY-MM-DD? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我从机器可读代码中获取日期格式为 YYMMDD 如何将其更改为 YYYY MM DD 例如我收到 871223 YYMMDD 我想把它改成
  • 将人类日期(当地时间 GMT)转​​换为日期

    我正在服务器上工作 服务器正在向我发送 GMT 本地日期的日期 例如Fri Jun 22 09 29 29 NPT 2018在字符串格式上 我将其转换为日期 如下所示 SimpleDateFormat simpleDateFormat ne
  • Akka 与现有 java 项目集成的示例

    如果我已经有现有的javaWeb 应用程序使用spring and servlet容器 将 Akka 集成到其中的正确方法是什么 就像我将会有Actor1 and Actor2互相沟通的 开始使用这些演员的切入点是什么 例如 1 把它放在那
  • 蓝牙发送和接收文本数据

    我是 Android 开发新手 我想制作一个使用蓝牙发送和接收文本的应用程序 我得到了有关发送文本的所有内容逻辑工作 但是当我尝试在手机中测试它时 我看不到界面 这是Main Activity Code import android sup
  • 如何在JPanel中设置背景图片

    你好 我使用 JPanel 作为我的框架的容器 然后我真的想在我的面板中使用背景图片 我真的需要帮助 这是我到目前为止的代码 这是更新 请检查这里是我的代码 import java awt import javax swing import
  • 轻松的反应

    我有一个与这里描述的类似的案例 动态更改RESTEasy服务返回类型 https stackoverflow com questions 3786781 dynamically change resteasy service return
  • 在 Spring 上下文中查找方法级自定义注释

    我想知道的是 所有的类 方法Spring http en wikipedia org wiki Spring Framework注释为 Versioned的bean 我创建了自定义注释 Target ElementType METHOD E
  • partitioningBy 必须生成一个包含 true 和 false 条目的映射吗?

    The 分区依据 https docs oracle com javase 8 docs api java util stream Collectors html partitioningBy java util function Pred
  • Android View Canvas onDraw 未执行

    我目前正在开发一个自定义视图 它在画布上绘制一些图块 这些图块是从多个文件加载的 并将在需要时加载 它们将由 AsyncTask 加载 如果它们已经加载 它们只会被绘制在画布上 这工作正常 如果加载了这些图片 AsyncTask 就会触发v
  • Java 11 - 将 Spring @PostConstruct 替换为 afterPropertiesSet 或使用 initMethod

    我正在使用 spring 应用程序 有时会使用 PostConstruct用于代码和测试中的设置 看来注释将被排除在外Java 11 https www baeldung com spring postconstruct predestro

随机推荐

  • WCF中的WS是什么意思?

    在wcf中 什么是WS 在WCF中是什么意思 有什么理由将其分组吗 它们是 Web 服务 WS 标准 这篇博文解释一下 WCF 实现的那些 将它们分组是因为它们共同构成了 WS 架构
  • 从 int 到 shared_ptr 的隐式转换

    考虑下面的代码 include
  • 如何拆分分隔字符串以便可以访问单个项目?

    使用 SQL Server 如何拆分字符串以便可以访问项目 x 取一个字符串 Hello John Smith 如何按空格分割字符串并访问索引 1 处应返回 John 的项目 我不相信 SQL Server 有内置的 split 函数 所以
  • 具有交互项的固定效应回归会导致错误

    我正在尝试使用表示路线的地理区域 LoadArea DischargeArea 的交互项来估计面板数据集 使用固定效应规范 它不喜欢交互项 LoadArea DischargeArea 并且在汇总回归时会产生以下错误 mult fe lt
  • 为什么浏览器允许关闭 Javascript? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 我很好奇为什么现代浏览器允许关闭 Javascript 现在很清楚 要做任何实质性的现代 Web 应用程序 您都需要集成一些高级别的 Javascript 为什么 javascript 不
  • Windows Phone 创建像 Facebook 一样的侧边菜单栏

    我是 Windows Phone 7 开发新手 我正在尝试创建类似于 Facebook 上使用的侧菜单栏 我创造了usercontrol并添加了不同屏幕的按钮 我还创建了PhoneApplicationPage并添加了一个按钮 当我单击该按
  • MATLAB:设置要并行应用的线条的颜色和样式顺序

    当你设置DefaultAxesColorOrder and DefaultAxesLineStyleOrderMATLAB 将首先循环使用第一种样式的所有颜色 然后再次使用第二种样式循环使用所有颜色 依此类推 看到这个文档 or 相关问题
  • Scala - 柯里化和默认参数

    我有一个带有两个参数列表的函数 我试图部分应用并与柯里化一起使用 第二个参数列表包含所有具有默认值 但不是隐式的 的参数 像这样的东西 def test a Int b Int 2 c Int 3 println a b c 现在 以下一切
  • 如何在Delphi中跟踪TScrollBox的滚动

    有没有简单的方法可以用滚动条跟踪 TScrollbox 内容的滚动 我有几个 TScrollBox 组件 每个组件内部都有一些组件 并且希望保持它们同步 如果其中一个滚动框滚动 垂直或水平 我需要同步滚动其他滚动框 这就是为什么我需要知道滚
  • SQLite Changes() 计算未更改的更新

    我对 SQLite 有疑问changes 函数 根据文档 返回最近完成的 INSERT DELETE 或 UPDATE 语句更改 插入或删除的数据库行数 另请参阅底层 C C 函数的文档 我希望使用这个函数来检查是否执行了UPDATE与单行
  • 转义转义字符

    我正在尝试模仿json encode在 PHP 5 3 0 中实现的位掩码标志 这是我的字符串 s addslashes O Rei lly O Rei lly Doing json encode s JSON HEX APOS JSON
  • SQL Server中存在重复行时如何选择具有最大值的行

    我有这样的桌子 DocumentID MasterStepID StepNumber RoleID UserID Status JIEP TT 07 000174 Approval1 1 NULL 0006100022 1 JIEP TT
  • 如何为使用canvas绘制的内容设置ontouch监听器:Android

    我有一个自定义视图 在其中画一个大圆圈 并在这个大圆圈的边缘画一个小圆圈 我想移动小圆圈 因此希望有一个仅用于小圆圈的 ontouch 侦听器 有人可以告诉我如何仅为小圆圈设置 ontouch 侦听器吗 public class Therm
  • JupyterLab:如何使用键盘快捷键清除当前单元格的输出?

    这个问题已针对 Jupyter 提出并回答笔记本电脑 here 有一个关于 Jupyter 的建议Lab还有关于如何hide单元格输出 但不清除它 使用下面的菜单很容易Edit gt Clear Outputs 但是如何使用键盘快捷键来做到
  • 将数据类型 nvarchar 转换为 datetime 时出错

    我有以下程序界面 Create procedure dbo InsertItemDetails TimeItemAdded datetime 当我这样称呼它时 EXEC dbo InsertItemDetails TimeItemAdded
  • 横滚、俯仰、偏航计算

    如何计算与齐次变换矩阵相关的横滚角 俯仰角和偏航角 我目前正在使用以下公式 但我不确定它们是否正确 pitch atan2 r20 sqrt r21 r21 r22 r22 yaw atan2 r10 r00 roll atan2 r21
  • Nest JS GraphQL“不能为不可为空返回 null”[重复]

    这个问题在这里已经有答案了 我尝试解决我的学习代码中的一个错误 但失败了 然后我尝试启动这段代码 https github com nestjs nest tree master sample 23 type graphql 并且同样的情况
  • UIAlertAction 按钮文本左对齐

    I want to align UIAlertAction text alignment to Left and add the icon as in image shown I spent lot of time on google to
  • Javascript 检测 Skype?

    某些 JavaScript 是否可以检测 Skype 是否安装 我问的原因是我想根据以下内容更改链接的 href 如果未安装 Skype 则显示一个弹出窗口 解释 Skype 是什么以及如何安装它 如果已安装 请将链接更改为skype my
  • 为什么Java中必须声明接口?

    有时 我们有多个类 它们的某些方法具有相同的签名 但与声明的 Java 接口不对应 例如 两者JTextField and JButton 其中包括其他几个javax swing 有一个方法 public void addActionLis