编辑:从 Java 8 开始,接口(interface)中现在允许使用静态方法。
这是示例:
public interface IXMLizable<T>
{
static T newInstanceFromXML(Element e);
Element toXMLElement();
}
这当然行不通。但为什么不呢?
可能的问题之一是,当您调用时会发生什么:
IXMLizable.newInstanceFromXML(e);
在这种情况下,我认为它应该只调用一个空方法(即 {})。所有子类都将被强制实现静态方法,因此在调用静态方法时它们都可以。那为什么这不可能呢?
编辑:我想我正在寻找比“因为 Java 就是这样”更深入的答案。
静态方法不能被覆盖是否有特定的技术原因?也就是说,为什么 Java 的设计者决定使实例方法可覆盖而不是静态方法?
编辑:我的设计的问题是我试图使用接口(interface)来强制执行编码约定。
也就是说,接口(interface)的目标是双重的:
除了在界面中添加评论之外,还有其他方法可以确保这一点吗?
最佳答案
Java 8 允许静态接口(interface)方法
在 Java 8 中,接口(interface)可以有静态方法。它们也可以有具体的实例方法,但不能有实例字段。
这里真的有两个问题:
接口(interface)中的静态方法
在以前的版本中,接口(interface)不能有静态方法并没有很强的技术原因。这是summed up nicely by the poster一个重复的问题。静态接口(interface)方法最初被认为是 a small language change,然后是 an official proposal在 Java 7 中添加它们,但后来 dropped due to unforeseen complications.
最后,Java 8 引入了静态接口(interface)方法,以及具有默认实现的可覆盖实例方法。他们仍然不能有实例字段。这些特性是 lambda 表达式支持的一部分,您可以在 Part H of JSR 335. 中阅读更多关于它们的信息。
覆盖静态方法
第二个问题的答案稍微复杂一些。
静态方法在编译时是可解析的。动态分派(dispatch)对于实例方法很有意义,其中编译器无法确定对象的具体类型,因此无法解析要调用的方法。但是调用静态方法需要一个类,并且由于该类是静态已知的——在编译时——动态分派(dispatch)是不必要的。
关于实例方法如何工作的一些背景知识对于理解这里发生的事情是必要的。我确信实际的实现是完全不同的,但是让我解释一下我的方法调度的概念,它可以准确地模拟观察到的行为。
假设每个类都有一个哈希表,将方法签名(名称和参数类型)映射到实际的代码块以实现该方法。当虚拟机尝试调用实例上的方法时,它会查询对象的类并在类的表中查找请求的签名。如果找到方法体,则调用它。否则,获取该类的父类,并在那里重复查找。这将继续直到找到该方法,或者没有更多的父类——这导致
NoSuchMethodError
.如果父类(super class)和子类在它们的表中都有相同方法签名的条目,则首先遇到子类的版本,并且从不使用父类(super class)的版本——这是“覆盖”。
现在,假设我们跳过对象实例并从一个子类开始。解决方案可以按上述方式进行,为您提供一种“可覆盖的”静态方法。然而,解析都可以在编译时发生,因为编译器从一个已知的类开始,而不是等到运行时才为它的类查询未指定类型的对象。 “覆盖”静态方法没有意义,因为人们总是可以指定包含所需版本的类。
构造函数“接口(interface)”
这里有更多 Material 来解决最近对该问题的编辑。
听起来您想为
IXMLizable
的每个实现有效地授权一个类似构造函数的方法。 .暂时不要尝试使用接口(interface)来强制执行此操作,并假装您有一些满足此要求的类。你会如何使用它?class Foo implements IXMLizable<Foo> {
public static Foo newInstanceFromXML(Element e) { ... }
}
Foo obj = Foo.newInstanceFromXML(e);
由于您必须明确命名具体类型
Foo
在“构造”新对象时,编译器可以验证它确实具有必要的工厂方法。如果没有,那又怎样?如果我可以实现一个 IXMLizable
缺少“构造函数”,我创建了一个实例并将其传递给您的代码,它是 IXMLizable
具有所有必要的界面。构造是实现的一部分,而不是接口(interface)。任何与接口(interface)一起成功运行的代码都不关心构造函数。任何关心构造函数的代码无论如何都需要知 Prop 体类型,接口(interface)可以忽略。
关于java - 为什么我不能在 Java 接口(interface)中定义静态方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/512877/