为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我不能在Java接口中定义一个静态方法?

为什么我不能在Java接口中定义一个静态方法?

慕仙森 2019-06-28 15:31:46
为什么我不能在Java接口中定义一个静态方法? 从Java 8开始,接口中允许使用静态方法。下面是一个例子:public interface IXMLizable<T>{   static T newInstanceFromXML(Element e);   Element toXMLElement();}这当然行不通。但为什么不呢?其中一个可能的问题是,当您调用:IXMLizable.newInstanceFromXML(e);在这种情况下,我认为应该调用一个空方法(即{})。所有子类都将被迫实现静态方法,因此在调用静态方法时它们都会很好。为什么这不可能?编辑:我想我是在寻找比“因为Java就是这样”更深层次的答案。为什么静态方法不能被覆盖,有什么特殊的技术原因吗?也就是说,为什么Java的设计者决定使实例方法可重写,而不是静态方法?编辑:我的设计的问题在于我试图使用接口来执行编码约定。也就是说,接口的目标有两个:我希望IXMLable接口允许我将实现它的类转换为XML元素(使用多态性,工作正常)。如果有人想要创建一个实现IXML接口的类的新实例,他们将始终知道会有一个newInstanceFromXML(Elemente)静态构造函数。除了在界面中添加注释之外,还有其他方法来确保这一点吗?
查看完整描述

3 回答

?
阿晨1998

TA贡献2037条经验 获得超6个赞

Java 8允许静态接口方法

使用Java 8,接口能,会,可以有静态的方法。它们也可以有具体的实例方法,但不具有实例字段。

这里确实有两个问题:

  1. 为什么在过去的糟糕时期,接口不能包含静态方法?
  2. 为什么不能重写静态方法?

接口中的静态方法

在以前的版本中,接口不可能有静态方法,这在技术上没有很强的原因。这是海报总结得很好一个重复的问题。静态接口方法最初被认为是小小的语言变化,然后正式提案将它们添加到Java 7中,但后来由于意外的并发症而下降。

最后,Java 8引入了静态接口方法,以及具有默认实现的可重写实例方法。但是他们仍然不能拥有实例字段。这些特性是lambda表达式支持的一部分,您可以在JSR 335 H部分。

覆盖静态方法

第二个问题的答案有点复杂。

静态方法在编译时是可解析的。例如,动态分派方法是有意义的,编译器无法确定对象的具体类型,因此无法解析要调用的方法。但是调用静态方法需要一个类,而且因为这个类是已知的。静态-在编译时-动态分派是不必要的。

对于实例方法是如何工作的,了解一下这里发生了什么是必要的。我确信实际的实现是完全不同的,但是让我解释一下我的方法分派的概念,哪种模型能够准确地观察到行为。

假设每个类都有一个哈希表,该哈希表将方法签名(名称和参数类型)映射到实际的代码块以实现该方法。当虚拟机试图在实例上调用方法时,它会查询对象的类,并在类的表中查找请求的签名。如果找到方法体,则调用它。否则,将获得该类的父类,并在其中重复查找。直到找到该方法,或者没有更多的父类,这将导致NoSuchMethodError.

如果超类和子类的表中都有相同方法签名的条目,则首先会遇到子类的版本,而超类的版本永远不会被使用-这是一个“覆盖”。

现在,假设我们跳过对象实例,从一个子类开始。决议可以按照上面的方式进行,给出一种“可覆盖的”静态方法。但是,解析可以在编译时发生,因为编译器是从已知的类开始的,而不是等到运行时才为其类查询未指定类型的对象。“重写”静态方法没有意义,因为可以始终指定包含所需版本的类。


构造器“接口”

这里有一些更多的材料来解决这个问题的最近的编辑。

的每个实现都需要有效地强制执行一个类似构造函数的方法。IXMLizable..忘记尝试用一个接口来执行这个操作一分钟,并假装您有一些类满足这个要求。你怎么用?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }}Foo obj = Foo.newInstanceFromXML(e);

因为您必须显式地命名具体类型。Foo当“构造”新对象时,编译器可以验证它确实有必要的工厂方法。如果没有,那又怎样?如果我能够实现IXMLizable它缺少“构造函数”,我创建一个实例并将其传递给您的代码。IXMLizable所有必要的接口。

建筑是实施的一部分,不是界面。任何成功使用接口的代码都不关心构造函数。任何关心构造函数的代码都需要知道具体的类型,接口可以被忽略。


查看完整回答
反对 回复 2019-06-28
?
繁星淼淼

TA贡献1775条经验 获得超11个赞

这个问题已经被询问和回答了,这里

重复我的答案:

在接口中声明静态方法是没有意义的。它们不能由普通调用MyInterface.staticMethod()执行。如果您通过指定实现类MyImplementor.staticMethod()来调用它们,那么您必须知道实际的类,因此接口是否包含它是无关紧要的。

更重要的是,静态方法永远不会被覆盖,如果您尝试这样做:

MyInterface var = new MyImplementingClass();var.staticMethod();

静态规则说,必须执行在声明的var类型中定义的方法。因为这是一个接口,这是不可能的。

不能执行“Result=MyInterface.staticMethod()”的原因是,它必须执行MyInterface中定义的方法的版本。但是不能在MyInterface中定义一个版本,因为它是一个接口。从定义上看,它没有代码。

虽然您可以说这相当于“因为Java是这样做的”,但在现实中,这个决定是其他设计决策的逻辑结果,也是有很好的理由做出的。


查看完整回答
反对 回复 2019-06-28
?
RISEBY

TA贡献1856条经验 获得超5个赞

通常这是使用工厂模式完成的

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);}public interface IXMLizable {
  public Element toXMLElement();}


查看完整回答
反对 回复 2019-06-28
  • 3 回答
  • 1 关注
  • 1302 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信