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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/512877/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:36:37  来源:igfitidea点击:

Why can't I define a static method in a Java interface?

javainterfacestatic-methods

提问by cdmckay

EDIT:As of Java 8, static methods are now allowed in interfaces.

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

Here's the example:

这是示例:

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

Of course this won't work. But why not?

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

One of the possible issues would be, what happens when you call:

可能的问题之一是,当您致电时会发生什么:

IXMLizable.newInstanceFromXML(e);

In this case, I think it should just call an empty method (i.e. {}). All subclasses would be forced to implement the static method, so they'd all be fine when calling the static method. So why isn't this possible?

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

EDIT:I guess I'm looking for answer that's deeper than "because that's the way Java is".

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

Is there a particular technological reason why static methods can't be overwritten? That is, why did the designers of Java decide to make instance methods overrideable but not static methods?

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

EDIT:The problem with my design is I'm trying to use interfaces to enforce a coding convention.

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

That is, the goal of the interface is twofold:

也就是说,接口的目标是双重的:

  1. I want the IXMLizable interface to allow me to convert classes that implement it to XML elements (using polymorphism, works fine).

  2. If someone wants to make a new instance of a class that implements the IXMLizable interface, they will always know that there will be a newInstanceFromXML(Element e) static constructor.

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

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

Is there any other way to ensure this, other than just putting a comment in the interface?

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

采纳答案by erickson

Java 8 permits static interface methods

Java 8 允许静态接口方法

With Java 8, interfaces canhave static methods. They can also have concrete instance methods, but not instance fields.

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

There are really two questions here:

这里真的有两个问题:

  1. Why, in the bad old days, couldn't interfaces contain static methods?
  2. Why can't static methods be overridden?
  1. 为什么在糟糕的过去,接口不能包含静态方法?
  2. 为什么不能覆盖静态方法?

Static methods in interfaces

接口中的静态方法

There was no strong technical reason why interfaces couldn't have had static methods in previous versions. This is summed up nicely by the posterof a duplicate question. Static interface methods were initially considered as a small language change,and then there was an official proposalto add them in Java 7, but it was later dropped due to unforeseen complications.

在以前的版本中,接口不能有静态方法并没有很强的技术原因。重复问题的海报很好地总结了这一点。静态接口方法最初被认为是一个小的语言变化,然后有官方提议在 Java 7 中添加它们,但后来由于无法预料的复杂性而删除。

Finally, Java 8 introduced static interface methods, as well as override-able instance methods with a default implementation. They still can't have instance fields though. These features are part of the lambda expression support, and you can read more about them in Part H of JSR 335.

最后,Java 8 引入了静态接口方法,以及具有默认实现的可覆盖实例方法。他们仍然不能有实例字段。这些特性是 lambda 表达式支持的一部分,您可以在JSR 335 的 H 部分阅读更多关于它们的信息

Overriding static methods

覆盖静态方法

The answer to the second question is a little more complicated.

第二个问题的答案稍微复杂一些。

Static methods are resolvable at compile time. Dynamic dispatch makes sense for instance methods, where the compiler can't determine the concrete type of the object, and, thus, can't resolve the method to invoke. But invoking a static method requires a class, and since that class is known statically—at compile time—dynamic dispatch is unnecessary.

静态方法在编译时是可解析的。动态分派对于实例方法是有意义的,其中编译器无法确定对象的具体类型,因此无法解析要调用的方法。但是调用静态方法需要一个类,并且由于该类是静态已知的——在编译时——动态分派是不必要的。

A little background on how instance methods work is necessary to understand what's going on here. I'm sure the actual implementation is quite different, but let me explain my notion of method dispatch, which models observed behavior accurately.

关于实例方法如何工作的一点背景知识对于理解这里发生的事情是必要的。我确信实际的实现是完全不同的,但让我解释一下我的方法调度的概念,它可以准确地模拟观察到的行为。

Pretend that each class has a hash table that maps method signatures (name and parameter types) to an actual chunk of code to implement the method. When the virtual machine attempts to invoke a method on an instance, it queries the object for its class and looks up the requested signature in the class's table. If a method body is found, it is invoked. Otherwise, the parent class of the class is obtained, and the lookup is repeated there. This proceeds until the method is found, or there are no more parent classes—which results in a NoSuchMethodError.

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

If a superclass and a subclass both have an entry in their tables for the same method signature, the sub class's version is encountered first, and the superclass's version is never used—this is an "override".

如果超类和子类在它们的表中都有相同方法签名的条目,则首先遇到子类的版本,并且从不使用超类的版本——这是“覆盖”。

Now, suppose we skip the object instance and just start with a subclass. The resolution could proceed as above, giving you a sort of "overridable" static method. The resolution can all happen at compile-time, however, since the compiler is starting from a known class, rather than waiting until runtime to query an object of an unspecified type for its class. There is no point in "overriding" a static method since one can always specify the class that contains the desired version.

现在,假设我们跳过对象实例并从一个子类开始。解决方案可以按上述方式进行,为您提供一种“可覆盖”的静态方法。然而,解析都可以在编译时发生,因为编译器从一个已知的类开始,而不是等到运行时才查询未指定类型的对象的类。“覆盖”静态方法没有意义,因为人们总是可以指定包含所需版本的类。



Constructor "interfaces"

构造函数“接口”

Here's a little more material to address the recent edit to the question.

这里有更多材料来解决最近对该问题的编辑。

It sounds like you want to effectively mandate a constructor-like method for each implementation of IXMLizable. Forget about trying to enforce this with an interface for a minute, and pretend that you have some classes that meet this requirement. How would you use it?

听起来您想为IXMLizable. 暂时不要尝试使用接口来强制执行此操作,并假装您有一些满足此要求的类。你会如何使用它?

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

Foo obj = Foo.newInstanceFromXML(e);

Since you have to explicitly name the concrete type Foowhen "constructing" the new object, the compiler can verify that it does indeed have the necessary factory method. And if it doesn't, so what? If I can implement an IXMLizablethat lacks the "constructor", and I create an instance and pass it to your code, it isan IXMLizablewith all the necessary interface.

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

Construction is part of the implementation,not the interface. Any code that works successfully with the interface doesn't care about the constructor. Any code that cares about the constructor needs to know the concrete type anyway, and the interface can be ignored.

构造是实现的一部分,而不是接口。任何与接口一起成功运行的代码都不关心构造函数。任何关心构造函数的代码无论如何都需要知道具体类型,接口可以忽略。

回答by Michael Myers

Because static methods cannot be overridden in subclasses, and hence they cannot be abstract. And all methods in an interface are, de facto, abstract.

因为静态方法不能在子类中被覆盖,因此它们不能是抽象的。接口中的所有方法实际上都是抽象的。

回答by samoz

Interfaces just provide a list of things a class will provide, not an actual implementation of those things, which is what your static item is.

接口只是提供一个类将提供的东西的列表,而不是这些东西的实际实现,这就是你的静态项目。

If you want statics, use an abstract class and inherit it, otherwise, remove the static.

如果需要静态,请使用抽象类并继承它,否则,删除静态。

Hope that helps!

希望有帮助!

回答by MichaelGG

Well, without generics, static interfaces are useless because all static method calls are resolved at compile time. So, there's no real use for them.

好吧,没有泛型,静态接口是无用的,因为所有静态方法调用都是在编译时解析的。所以,它们没有真正的用处。

With generics, they have use -- with or without a default implementation. Obviously there would need to be overriding and so on. However, my guess is that such usage wasn't very OO (as the other answers point out obtusely) and hence wasn't considered worth the effort they'd require to implement usefully.

对于泛型,他们可以使用 -- 有或没有默认实现。显然,需要覆盖等等。但是,我的猜测是,这种用法不是很面向对象(正如其他答案迟钝地指出的那样),因此被认为不值得他们为有效实施而付出的努力。

回答by cliff.meyers

Interfaces are concerned with polymorphism which is inherently tied to object instances, not classes. Therefore static doesn't make sense in the context of an interface.

接口与多态性有关,多态性本质上与对象实例而非类相关联。因此,静态在接口的上下文中没有意义。

回答by Handerson

You can't define static methods in an interface because static methods belongs to a class not to an instance of class, and interfaces are not Classes. Read more here.

您不能在接口中定义静态方法,因为静态方法属于类而不属于类的实例,并且接口不是类。在这里阅读更多。

However, If you want you can do this:

但是,如果您愿意,可以这样做:

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

In this case what you have is two classes with 2 distinct static methods called methodX().

在这种情况下,您拥有的是两个具有 2 个不同静态方法的类,称为 methodX()。

回答by DJClayworth

This was already asked and answered, here

这已经被问过并回答过,这里

To duplicate my answer:

复制我的答案:

There is never a point to declaring a static method in an interface. They cannot be executed by the normal call MyInterface.staticMethod(). If you call them by specifying the implementing class MyImplementor.staticMethod() then you must know the actual class, so it is irrelevant whether the interface contains it or not.

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

More importantly, static methods are never overridden, and if you try to do:

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

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

the rules for static say that the method defined in the declared type of var must be executed. Since this is an interface, this is impossible.

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

The reason you can't execute "result=MyInterface.staticMethod()" is that it would have to execute the version of the method defined in MyInterface. But there can't be a version defined in MyInterface, because it's an interface. It doesn't have code by definition.

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

While you can say that this amounts to "because Java does it that way", in reality the decision is a logical consequence of other design decisions, also made for very good reason.

虽然您可以说这相当于“因为 Java 是这样做的”,但实际上该决定是其他设计决定的合乎逻辑的结果,也是有充分理由做出的。

回答by Adrian Pronk

Static methods aren't virtual like instance methods so I suppose the Java designers decided they didn't want them in interfaces.

静态方法不像实例方法那样是虚拟的,所以我想 Java 设计者决定他们不希望它们出现在接口中。

But you can put classes containing static methods inside interfaces. You could try that!

但是您可以将包含静态方法的类放在接口中。你可以试试!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}

回答by Pavel Feldman

I think java does not have static interface methods because you do not need them. You may think you do, but... How would you use them? If you want to call them like

我认为 java 没有静态接口方法,因为您不需要它们。你可能认为你这样做了,但是......你会如何使用它们?如果你想这样称呼他们

MyImplClass.myMethod()

then you do not need to declare it in the interface. If you want to call them like

那么你不需要在接口中声明它。如果你想这样称呼他们

myInstance.myMethod()

then it should not be static. If you are actually going to use first way, but just want to enforce each implementation to have such static method, then it is really a coding convention, not a contract between instance that implements an interface and calling code.

那么它不应该是静态的。如果你真的打算使用第一种方式,但只是想强制每个实现都有这样的静态方法,那么它实际上是一种编码约定,而不是实现接口和调用代码的实例之间的契约。

Interfaces allow you to define contract between instance of class that implement the interface and calling code. And java helps you to be sure that this contract is not violated, so you can rely on it and don't worry what class implements this contract, just "someone who signed a contract" is enough. In case of static interfaces your code

接口允许您在实现接口的类实例和调用代码之间定义契约。而java帮助你确定这个契约没有被违反,所以你可以依赖它,不用担心这个契约是什么类实现的,只要“签了契约的人”就够了。如果是静态接口,您的代码

MyImplClass.myMethod()

does not rely on the fact that each interface implementation has this method, so you do not need java to help you to be sure with it.

不依赖于每个接口实现都有这个方法的事实,所以你不需要 java 来帮助你确定它。

回答by u7867

Several answers have discussed the problems with the concept of overridable static methods. However sometimes you come across a pattern where it seems like that's just what you want to use.

几个答案讨论了可覆盖静态方法概念的问题。然而,有时您会遇到一种模式,看起来这正是您想要使用的。

For example, I work with an object-relational layer that has value objects, but also has commands for manipulating the value objects. For various reasons, each value object class has to define some static methods that let the framework find the command instance. For example, to create a Person you'd do:

例如,我使用一个具有值对象的对象关系层,但也有用于操作值对象的命令。由于各种原因,每个值对象类都必须定义一些静态方法,让框架找到命令实例。例如,要创建一个 Person 你会这样做:

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

and to load a Person by ID you'd do

并按您的 ID 加载一个人

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

This is fairly convenient, however it has its problems; notably the existence of the static methods can not be enforced in the interface. An overridable static method in the interface would be exactly what we'd need, if only it could work somehow.

这是相当方便的,但是它有它的问题;值得注意的是,静态方法的存在不能在接口中强制执行。接口中可覆盖的静态方法正是我们所需要的,只要它能够以某种方式工作。

EJBs solve this problem by having a Home interface; each object knows how to find its Home and the Home contains the "static" methods. This way the "static" methods can be overridden as needed, and you don't clutter up the normal (it's called "Remote") interface with methods that don't apply to an instance of your bean. Just make the normal interface specify a "getHome()" method. Return an instance of the Home object (which could be a singleton, I suppose) and the caller can perform operations that affect all Person objects.

EJB 通过 Home 接口解决了这个问题;每个对象都知道如何找到它的 Home 并且 Home 包含“静态”方法。通过这种方式,可以根据需要覆盖“静态”方法,并且您不会将正常(称为“远程”)接口与不适用于 bean 实例的方法混在一起。只需让普通接口指定一个“getHome()”方法即可。返回 Home 对象的一个​​实例(我想这可能是一个单例),调用者可以执行影响所有 Person 对象的操作。