为什么我无法在Java界面中定义静态方法?

这是一个例子:

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

当然这是行不通的。 但为什么不呢?

其中一个可能的问题是,当你打电话时会发生什么:

IXMLizable.newInstanceFromXML(e);

在这种情况下,我认为它应该只调用一个空方法(即{})。 所有的子类都将被迫实现静态方法,所以在调用静态方法时它们都会很好。 那为什么不可能呢?

编辑:我想我正在寻找比“因为这是Java的方式”更深的答案。

是否有一个特定的技术原因,为什么静态方法不能被覆盖? 也就是说,为什么Java的设计者决定让实例方法可覆盖而不是静态方法?

编辑:我的设计问题是我试图使用接口来强制执行编码约定。

也就是说,界面的目标是双重的:

  • 我希望IXMLizable接口允许我将实现它的类转换为XML元素(使用多态性,工作正常)。

  • 如果有人想创建一个实现IXMLizable接口的类的新实例,他们将始终知道将会有一个newInstanceFromXML(Element e)静态构造函数。

  • 除了在界面中添加评论之外,还有其他方法可以确保这一点吗?

    编辑:从Java 8开始,现在允许在接口中使用静态方法。


    Java 8允许使用静态接口方法

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

    这里真的有两个问题:

  • 为什么在过去不好的时候,接口不能包含静态方法?
  • 为什么不能重写静态方法?
  • 接口中的静态方法

    没有强有力的技术原因,为什么接口在以前的版本中不能使用静态方法。 这是由一个重复问题的海报很好地总结。 静态接口方法最初被认为是一种小小的语言变化,然后有一个官方建议将它们添加到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

    结构是实现的一部分,而不是接口。 任何与接口成功工作的代码都不关心构造函数。 任何关心构造函数的代码都需要知道具体类型,并且可以忽略该接口。


    这里已经提出并回答了这个问题

    要复制我的答案:

    在界面中声明一个静态方法从来没有任何意义。 它们不能通过正常调用MyInterface.staticMethod()来执行。 如果你通过指定实现类MyImplementor.staticMethod()来调用它们,那么你必须知道实际的类,所以这个接口是否包含它是无关紧要的。

    更重要的是,静态方法不会被覆盖,如果你尝试去做:

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

    静态规则表示必须执行在声明的var类型中定义的方法。 由于这是一个界面,这是不可能的。

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

    虽然你可以说这等于“因为Java是这样做的”,但实际上这个决定是其他设计决策的逻辑结果,也是出于非常好的理由。


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

    public interface IXMLizableFactory<T extends IXMLizable> {
      public T newInstanceFromXML(Element e);
    }
    
    public interface IXMLizable {
      public Element toXMLElement();
    }
    
    链接地址: http://www.djcxy.com/p/20699.html

    上一篇: Why can't I define a static method in a Java interface?

    下一篇: In Java, what is a shallow copy?