为什么我不能在接口中声明静态方法?

Why can't I declare static methods in an interface?

提问人:Henrik Paul 提问时间:8/22/2008 最后编辑:skaffmanHenrik Paul 更新时间:2/21/2019 访问量:107520

问:

这个话题说得最多 - 静态方法不能在接口中声明的原因是什么?

public interface ITest {
    public static String test();
}

上面的代码给了我以下错误(至少在 Eclipse 中):“接口方法 ITest.test() 的非法修饰符;只允许公开和抽象”。

Java 接口 方法 静态

评论

2赞 Mnementh 9/26/2008
请不要接受 Espo 的回答,因为它是有缺陷的。接口有一个类文件,可以包含静态方法的实现(如果 Java 设计器允许这样做),因此解析静态方法的实现没有问题。它的工作方式与其他静态类完全相同。
0赞 Maverick 11/11/2013
我有点同意“埃里克森”给出的答案 stackoverflow.com/questions/512877/......
9赞 m0skit0 12/29/2013
顺便说一句,这将在 Java 8 中提供。
1赞 m0skit0 2/5/2014
@Vadorequest GIYF,但无论如何,请在此处查看
2赞 LoganMzz 4/22/2015
来自官方文档的链接:Java SE教程Java语言规范9.2

答:

7赞 Ryan Farley 8/22/2008 #1

静态方法不是实例方法。没有实例上下文,因此从接口实现它意义不大。

18赞 Kyle Cronin 8/22/2008 #2

我将用一个例子来回答你的问题。假设我们有一个带有静态方法添加的 Math 类。您可以像这样调用此方法:

Math.add(2, 3);

如果 Math 是一个接口而不是一个类,它就不能有任何定义的函数。因此,说像 Math.add(2, 3) 这样的东西是没有意义的。

45赞 Espo 8/22/2008 #3

接口中不能有静态方法的原因在于 Java 解析静态引用的方式。Java 在尝试执行静态方法时不会费心寻找类的实例。这是因为静态方法不依赖于实例,因此可以直接从类文件执行。鉴于接口中的所有方法都是抽象的,VM 必须查找接口的特定实现,以便找到静态方法背后的代码,以便可以执行它。这与静态方法解析的工作方式相矛盾,并且会在语言中引入不一致。

评论

3赞 Mnementh 9/26/2008
这种解释并不能解释问题。每个接口都有自己的类文件,它可以包含静态方法。因此,不需要查找特定的实现。
0赞 Vlad Gudim 2/6/2009
并非 Java 中的每个接口类型都在它自己的文件中,也不应该根据 JLS。此外,JLS 并没有规定类必须始终存储在文件系统中,恰恰相反。
4赞 Mnementh 1/8/2011
@Totophil:接口不能在单个 java 文件中,但在编译后将有自己的类文件。这就是我写的。
2赞 Rob Cooper 8/22/2008 #4

接口用于多态性,它适用于对象,而不是类型。因此(如前所述)拥有静态接口成员是没有意义的。

评论

0赞 Cruncher 8/27/2013
不过,在某些反思的背景下,这似乎是有道理的
-2赞 FlySwat 8/22/2008 #5

也许代码示例会有所帮助,我将使用 C#,但您应该能够跟上。

让我们假设我们有一个叫做IPayable的界面

public interface IPayable
{
    public Pay(double amount);
}

现在,我们有两个具体的类来实现这个接口:

public class BusinessAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

public class CustomerAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

现在,让我们假设我们有一个各种帐户的集合,为此,我们将使用 IPayable 类型的通用列表

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

现在,我们想向所有这些帐户支付 50.00 美元:

foreach (IPayable account in accountsToPay)
{
    account.Pay(50.00);
}

所以现在你明白了接口是如何非常有用的。

它们仅用于实例化对象。不在静态类上。

如果您将支付设置为静态,则在 accountsToPay 中循环浏览 IPayable 时,将无法确定它是否应该在 BusinessAcount 或 CustomerAccount 上调用 pay。

评论

0赞 Cruncher 8/27/2013
仅仅因为静态方法在这个例子中没有意义,并不意味着它们在任何例子中都没有意义。在您的示例中,如果 IPayable 接口具有静态方法“IncrementPayables”,用于跟踪添加了多少应付账款,这将是一个实际用例。当然,人们总是可以使用抽象类,但这不是你所要解决的。您的示例本身不会破坏接口中的静态方法。
86赞 James A. Rosen 8/22/2008 #6

这里有一些问题在起作用。第一个问题是声明静态方法而不定义它的问题。这是两者的区别

public interface Foo {
  public static int bar();
}

public interface Foo {
  public static int bar() {
    ...
  }
}

由于 Espo 提到的原因,第一个是不可能的:你不知道哪个实现类是正确的定义。

Java 可以允许后者;事实上,从 Java 8 开始,它就做到了!

评论

2赞 peterk 6/21/2013
是的 - 这是思想上的,而不是技术上的。我想要它的原因是。可以在接口中有一个静态的“实现”方法,该方法仅引用接口中的其他“接口”方法,这些方法可以通过实现类轻松重用。但是可以在接口中声明一个静态,这样就可以让这样的东西驻留在那里,比如 MyInterface.Impl.doIt(MyInterface i, Object[] args) { ... }
9赞 Olivier Grégoire 6/25/2014
从 Java 8 开始,您可以在 .方法必须是 。staticinterfacepublic
5赞 William F. Jameson 8/7/2014
@OlivierGrégoire......而且它们不是遗传的,这是关键。
1赞 Timo 5/18/2015
很好的答案,虽然“大致等效”ROFLMAO xD,但我会把它说得更像“有点相似”。
11赞 Mnementh 9/26/2008 #7

原因在于设计原则,即 java 不允许多重继承。多重继承的问题可以通过以下示例来说明:

public class A {
   public method x() {...}
}
public class B {
   public method x() {...}
}
public class C extends A, B { ... }

现在,如果调用 C.x() 会发生什么?会执行 A.x() 还是 B.x()?每一种具有多重继承的语言都必须解决这个问题。

接口在 Java 中允许某种受限制的多重继承。为了避免上述问题,不允许它们有方法。如果我们用接口和静态方法看同样的问题:

public interface A {
   public static method x() {...}
}
public interface B {
   public static method x() {...}
}
public class C implements A, B { ... }

同样的问题在这里,如果你调用 C.x() 会发生什么?

评论

0赞 Mnementh 1/8/2011
投反对票有什么理由吗?解释性评论会很好。
0赞 nawfal 10/5/2012
我不是反对者,但这对非静态方法不也有效吗?
0赞 Mnementh 10/6/2012
好的,这里有两种不同的可能性。方法可以实现或仅声明。我明白,必须实现静态方法。从这个意义上说,我遇到了我的答案中提出的问题。如果你不这样做,你就会遇到 Espo 描述的问题——我不明白,因为我认为静态方法会被实现。由于这个原因,你也不能声明一个静态的抽象方法,试试看,编译器会抱怨的。
0赞 nawfal 10/6/2012
好吧,忘记实现部分。 问题是为什么我们不能声明。是的,编译器会抱怨,为什么这是个问题。我认为你还没有回答。
1赞 supercat 2/1/2013
那里的情况怎么会比拥有接口包含和接口包含更糟糕?接口C中的含义是什么?Aint x(int z);Bstring x(int x);x(3)
4赞 Zarkonnen 2/6/2009 #8

对于您的问题,这里有一个非常漂亮和简洁的答案。(它给我留下了深刻的印象,因为它是一种非常直接的解释方式,我想从这里链接它。

评论

0赞 CubeJockey 5/6/2016
这不是问题的答案,充其量应该是一个评论。
3赞 Lenik 9/17/2013 #9

似乎接口中的静态方法可能在 Java 8 中得到支持,好吧,我的解决方案只是在内部类中定义它们。

interface Foo {
    // ...
    class fn {
        public static void func1(...) {
            // ...
        }
    }
}

同样的技术也可以用在注释中:

public @interface Foo {
    String value();

    class fn {
        public static String getValue(Object obj) {
            Foo foo = obj.getClass().getAnnotation(Foo.class);
            return foo == null ? null : foo.value();
        }
    }
}

内部类应始终以 而不是 的形式访问,然后,您可以摆脱歧义问题。Interface.fn...Class.fn...

0赞 Sankar 10/2/2013 #10

修饰符的非法组合:静态和抽象

如果一个类的成员被声明为静态的,则可以将其与限制在该类中的类名一起使用,而无需创建对象。

如果一个类的成员被声明为抽象,则需要将该类声明为抽象,并且需要在其继承的类(Sub-Class)中提供抽象成员的实现。

您需要为子类中类的抽象成员提供一个实现,您将在其中更改静态方法的行为,该方法也被声明为抽象,它仅限于基类,这是不正确的

评论

0赞 Lucky 9/19/2016
这如何回答这个问题?OP 在你写类时询问了接口。
0赞 ip_x 12/15/2013 #11

由于静态方法不能被继承。所以把它放在界面里是没有用的。接口基本上是所有订阅者都必须遵守的合同。在接口中放置一个静态方法将迫使订阅者实现它。现在,这与静态方法不能被继承的事实相矛盾。

评论

0赞 Akki 2/28/2016
静态方法始终是继承的,但不能重写。
6赞 Anandaraja_Srinivasan 3/28/2014 #12

现在 Java8 允许我们在接口中定义静态方法。

interface X {
    static void foo() {
       System.out.println("foo");
    }
}

class Y implements X {
    //...
}

public class Z {
   public static void main(String[] args) {
      X.foo();
      // Y.foo(); // won't compile because foo() is a Static Method of X and not Y
   }
}

注意:默认情况下,如果我们不明确使用关键字 default/static 来使它们成为 Default 方法和 Static 方法,则默认情况下,Interface 中的方法仍然是公共抽象的。

1赞 Kumar Abhishek 2/5/2016 #13

Java 8 改变了世界,你可以在界面中使用静态方法,但它迫使你为此提供实现。

public interface StaticMethodInterface {
public static int testStaticMethod() {
    return 0;
}

/**
 * Illegal combination of modifiers for the interface method
 * testStaticMethod; only one of abstract, default, or static permitted
 * 
 * @param i
 * @return
 */
// public static abstract int testStaticMethod(float i);

default int testNonStaticMethod() {
    return 1;
}

/**
 * Without implementation.
 * 
 * @param i
 * @return
 */
int testNonStaticMethod(float i);

}

0赞 Ishara 2/21/2019 #14

Java 8 中,接口现在可以有静态方法。

例如,Comparator 有一个静态的 naturalOrder() 方法。

接口不能有实现的要求也放宽了。接口现在可以声明“默认”方法实现,这与普通实现类似,但有一个例外:如果同时从接口继承默认实现和从超类继承普通实现,则超类的实现将始终优先。

评论

0赞 Mohamed Anees A 2/21/2019
我的天啊!我们有一个认真的程序员(和我,评论者)回答(和我,评论)10 年前的问题。
0赞 Ishara 2/22/2019
我没有注意到日期:)
0赞 Mohamed Anees A 2/22/2019
哈哈!没关系!