为什么Interfaces中没有静态方法,但静态字段和内部类可以吗?

为什么不能在接口中定义静态方法,这里有几个问题,但是没有一个解决基本的不一致:为什么你可以在一个接口中定义静态字段和静态内部types,而不是静态方法?

静态的内部types可能不是一个公平的比较,因为这只是语法糖产生一个新的类,但为什么字段,而不是方法?

在接口中反对静态方法的一个参数是它打破了JVM使用的虚拟表格parsing策略,但不应该同样适用于静态字段,也就是说,编译器可以内联它吗?

一致性是我所希望的,Java应该在界面中不支持任何forms的静态,或者它应该是一致的,并允许它们。

已经提出了一个正式的提议 ,允许在Java 7中的接口中使用静态方法。这个提议是在Project Coin下进行的 。

我个人认为这是一个好主意。 实施没有技术难度,这是一个非常合理的逻辑。 Project Coin中有几个build议,我希望永远不会成为Java语言的一部分,但是这可以清理很多API。 例如, Collections类具有用于处理任何List实现的静态方法 ; 这些可以包含在List界面中。


更新:在“ Java Posse Podcast#234”中, Joe D'arcy简要地提到了这个提议,说这是“复杂的”,可能不会在Project Coin下进行。


更新:虽然他们没有把它变成Java 7的Project Coin,但Java 8确实支持接口中的静态函数。

我要和我的宠物理论一起去解决这个问题,就是这种情况下缺乏一致性是一个方便而不是devise或必要的问题,因为我没有听到任何有说服力的论点, 。

静态字段在那里(a),因为它们在JDK 1.0中,并且在JDK 1.0中做出了许多狡猾的决定,并且(b)接口中的静态final字段是当时Java最接近常数的东西。

接口中的静态内部类是允许的,因为这是纯粹的语法糖 – 内部类实际上并不是父类的任何东西。

所以静态方法是不允许的,因为没有强制性的理由。 一致性不足以改变现状。

当然,这可以在未来的JLS版本中被允许而不会破坏任何东西。

在接口中声明一个静态方法从没有任何意义。 它们不能通过正常的调用MyInterface.staticMethod()来执行。 (编辑:由于最后一句话困惑了一些人,调用MyClass.staticMethod()精确地执行MyClass上的staticMethod,如果MyClass是一个接口,它不能存在!)如果通过指定实现类MyImplementor.staticMethod()那么你必须知道实际的类,所以接口是否包含它是无关紧要的。

更重要的是,静态方法从来没有被覆盖,如果你尝试做:

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

静态规则说,必须执行在声明的vartypes中定义的方法。 既然这是一个界面,这是不可能的。

您当然可以始终从方法中删除static关键字。 一切都会正常工作。 如果从实例方法调用,可能需要禁止一些警告。

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

接口的目的是在不提供实现的情况下定义合同。 因此,你不能有静态方法,因为你不能覆盖静态方法,所以它们必须已经在接口中实现了。 至于字段,只允许静态final fields ,实质上是常量(在1.5+中,也可以在接口中枚举)。 这些常量有助于定义没有幻数的接口。

顺便说一句,没有必要为接口中的字段显式指定static final修饰符,因为只允许静态最终字段。

这是一个古老的线索,但这是一个非常重要的问题。 由于我今天才注意到这一点,所以我试图用更简洁的方式来解释它:

接口的主要目的是提供一些不可实现的东西,所以如果提供的话

静态方法是允许的

那么你可以使用interfaceName.staticMethodName()来调用该方法,但这是未实现的方法,并且不包含任何内容。 所以静态方法是无用的。 所以他们根本不提供这个。

静态字段是允许的

因为领域是不可实现的,通过可实现我的意思是你不能在现场执行任何逻辑操作,你可以在现场做操作。 所以你不改变领域的行为,这就是为什么他们被允许。

内部类是允许的

允许内部类,因为在编译之后,创build了不同的Inner类的类文件,说InterfaceName $ InnerClassName.class ,所以基本上你是在不同的实体中提供实现,但不是在接口中。 所以提供了在Inner类中的实现。

我希望这会有所帮助。

实际上有时候有人可以从静态方法中受益。 它们可以用作实现接口的类的工厂方法。 例如,这就是我们现在在openjdk中拥有Collection接口和Collections类的原因。 所以总是有一些解决方法 – 为另一个类提供一个私有的构造函数,它将作为静态方法的“命名空间”。

在Java 5之前,静态字段的常见用法是:

 interface HtmlConstants { static String OPEN = "<"; static String SLASH_OPEN = "</"; static String CLOSE = ">"; static String SLASH_CLOSE = " />"; static String HTML = "html"; static String BODY = "body"; ... } public class HtmlBuilder implements HtmlConstants { // implements ?!? public String buildHtml() { StringBuffer sb = new StringBuffer(); sb.append(OPEN).append(HTML).append(CLOSE); sb.append(OPEN).append(BODY).append(CLOSE); ... sb.append(SLASH_OPEN).append(BODY).append(CLOSE); sb.append(SLASH_OPEN).append(HTML).append(CLOSE); return sb.toString(); } } 

这意味着HtmlBuilder不必限制每个常量,所以它可以使用OPEN而不是HtmlConstants.OPEN

以这种方式使用工具最终是令人困惑的。

现在使用Java 5,我们使用导入静态语法来实现相同的效果:

 private final class HtmlConstants { ... private HtmlConstants() { /* empty */ } } import static HtmlConstants.*; public class HtmlBuilder { // no longer uses implements ... } 

在接口中没有静态方法没有真正的理由,除了:Java语言devise者不想这样做。 从技术angular度来看,允许他们是有道理的。 毕竟抽象类也可以拥有它们。 我假设但没有testing它,你可以“手工”字节代码接口有一个静态方法,它应该没有问题调用方法和/或通常使用接口。

我经常想知道为什么静态方法呢? 他们有它们的用途,但是包/名称空间级别的方法可能会覆盖80个用于静态方法的地方。

记住两个主要原因:

  1. Java中的静态方法不能被子类覆盖,这对静态字段来说是一个更大的方法。 在实践中,我甚至从来都不想重写子类中的字段,但我总是重写方法。 所以有静态方法阻止实现接口的类提供自己的方法实现,这在很大程度上挫败了使用接口的目的。

  2. 接口不应该有代码; 这就是抽象类的用途。 接口的要点是让你谈论可能不相关的对象,这些对象恰好都有一定的方法。 实际上,提供这些方法的实现超出了接口意图的范围。

静态方法绑定到一个类。 在Java中,接口在技术上不是类,而是types,但不是类(因此,关键字实现,接口不扩展对象)。 因为接口不是类,所以它们不能有静态方法,因为没有实际的类来附加。

您可以调用InterfaceName.class来获取与接口相对应的Class对象,但是Class类明确指出它代表了Java应用程序中的类和接口。 但是,接口本身不被视为一个类,因此您不能附加静态方法。

只有静态final字段可以在接口中声明(就像方法一样,即使你没有包含“public”关键字,静态字段是“final”,有或没有关键字)。

这些只是值,在编译时会被复制到字面上,所以你在运行时永远都不会真的“调用”静态字段。 有一个静态方法不会有相同的语义,因为它会涉及调用一个接口,而不实现,这是Java不允许的。

原因是在界面中定义的所有方法都是抽象的,不pipe你是否明确声明了该修饰符。 抽象静态方法不是修饰符的允许组合,因为静态方法不能被覆盖。

至于为什么接口允许静态字段。 我有一种感觉应该被认为是一个“特征”。 我能想到的唯一可能性就是将接口的实现感兴趣的常量组化。

我同意一致性会是一个更好的方法。 界面中不允许有静态成员。

我相信可以在不创build对象的情况下访问静态方法,并且该接口不允许创build对象,以限制程序员直接使用接口方法,而不是从其实现的类中使用接口方法。 但是如果你在一个接口中定义一个静态方法,你可以直接访问它而不需要实现。 因此在接口中不允许使用静态方法。 我不认为这种一致性应该是一个问题。

Java 1.8接口静态方法只对接口方法可见,如果我们从InterfaceExample类中移除methodSta1()方法,我们将无法将其用于InterfaceExample对象。 然而像其他静态方法一样,我们可以使用类名的接口静态方法。 例如,一个有效的语句将是:exp1.methodSta1();

所以在看下面的例子之后我们可以说:1)Java接口的静态方法是接口的一部分,我们不能用它来实现类对象。

2)Java接口的静态方法有利于提供实用的方法,比如空值检查,集合sorting,日志等。

3)Java接口静态方法通过不允许实现类(InterfaceExample)覆盖它们来帮助我们提供安全性。

4)我们无法定义Object类方法的接口静态方法,我们将会得到编译器错误,因为“这个静态方法不能从Object中隐藏实例方法”。 这是因为它不允许在java中,因为Object是所有类的基类,我们不能有一个类级别的静态方法和另一个具有相同签名的实例方法。

5)我们可以使用java接口的静态方法来移除集合等实用工具类,并将其所有的静态方法移动到相应的接口,这将很容易find和使用。

 public class InterfaceExample implements exp1 { @Override public void method() { System.out.println("From method()"); } public static void main(String[] args) { new InterfaceExample().method2(); InterfaceExample.methodSta2(); // <--------------------------- would not compile // methodSta1(); // <--------------------------- would not compile exp1.methodSta1(); } static void methodSta2() { // <-- it compile successfully but it can't be overridden in child classes System.out.println("========= InterfaceExample :: from methodSta2() ======"); } } interface exp1 { void method(); //protected void method1(); // <-- error //private void method2(); // <-- error //static void methodSta1(); // <-- error it require body in java 1.8 static void methodSta1() { // <-- it compile successfully but it can't be overridden in child classes System.out.println("========= exp1:: from methodSta1() ======"); } static void methodSta2() { // <-- it compile successfully but it can't be overridden in child classes System.out.println("========= exp1:: from methodSta2() ======"); } default void method2() { System.out.println("--- exp1:: from method2() ---");} //synchronized default void method3() { System.out.println("---");} // <-- Illegal modifier for the interface method method3; only public, abstract, default, static // and strictfp are permitted //final default void method3() { System.out.println("---");} // <-- error }