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


150

该主题充分说明了这一点-为什么不能在接口中声明静态方法的原因是什么?

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

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


2
请拒绝Espo的回答,因为它有缺陷。接口具有一个类文件,该文件可以包含静态方法的实现(如果Java设计人员允许这样做的话),因此解决静态方法的实现没有问题。它与其他静态类完全一样。
Mnementh

我有点同意“ erickson” stackoverflow.com/questions/512877/…
Maverick

9
这将在Java 8 btw中可用。
m0skit0 2013年

1
@Vadorequest GIYF但无论如何,请在这里查看
m0skit0 2014年

2
官方文档的链接:Java SE教程Java语言规范9.2
LoganMzz

Answers:


85

这里有一些问题。第一个问题是声明一个静态方法而不定义它的问题。这是之间的区别

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

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

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

Java 可以允许后者。实际上,从Java 8开始,它确实做到了!


2
是的-这是思想上的而不是技术上的。我想要的原因是。可以在接口中有一个静态的“实现”方法,该方法仅引用该接口中的其他“接口”方法,这些方法可以通过实现类轻松地重用。但是人们可以在接口中声明一个静态,因此可以在其中放置类似MyInterface.Impl.doIt(MyInterface i,Object [] args){...}
东西

9
从Java 8开始,您可以在中定义static方法interface。方法必须是public
OlivierGrégoire2014年

4
@OlivierGrégoire...并且它们没有被继承,这是关键。
威廉·詹姆森

1
好的答案,尽管“近似等效” ROFLMAO xD,但我会更像是“有点像”。
蒂莫,2015年

44

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


3
这种解释不能解释问题。每个接口都有自己的类文件,它可以包含静态方法。因此,无需查找特定的实现。
Mnementh's

并非Java中的每种接口类型都在其自己的文件中,也不应该根据JLS。另外,JLS并没有规定必须始终将类与文件系统一起存储,恰恰相反。
弗拉德·古迪姆09年

4
@Totophil:接口不得位于单个java文件中,但在编译后它将具有自己的类文件。那就是我写的
Mnementh 2011年

18

我将举例说明您的问题。假设我们有一个带有静态方法add的Math类。您将这样调用此方法:

Math.add(2, 3);

如果Math是接口而不是类,则它不能具有任何定义的函数。因此,说Math.add(2,3)之类的东西是没有道理的。


11

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

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

现在,如果您调用Cx()会发生什么?将执行Ax()还是Bx()?具有多重继承的每种语言都必须解决此问题。

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

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

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


反对的理由是什么?一个解释性的评论会很好。
Mnementh 2011年

我不是拒绝投票的人,但这对非静态方法也无效吗?
nawfal 2012年

好的,这是两种不同的可能性。可以实现或仅声明一个方法。我知道,必须执行静态方法。在这种意义上,我遇到了答案中提出的问题。如果您不这样做,则会遇到Espo所描述的问题-我不明白,因为我认为将实现静态方法。由于这个原因,您也不能声明静态抽象方法,请尝试一下,编译器会抱怨。
Mnementh

好的,忘记实现部分。问题是为什么我们不能宣布。是的,编译器会抱怨,这就是问题所在。我认为您没有回答。
nawfal 2012年

1
与接口A包含int x(int z);和接口B包含相比,情况如何会更糟string x(int x);x(3)接口C中的含义是什么?
2013年


5

现在,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中的方法仍然是公共抽象的。


4

这里,您的问题有一个非常简洁的答案。(它让我感到惊讶,因为它是一种非常简单明了的解释方式,我想从这里进行链接。)


这不是问题的答案,充其量应该是一条评论。
CubeJockey

3

看来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...,这样就可以摆脱模棱两可的问题。


2

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


在某些反思性背景下,这似乎几乎是有道理的
-Cruncher

1

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

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

如果一个类的成员被声明为静态的,则可以使用其类名(仅限于该类)使用,而无需创建对象。

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

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


这如何回答这个问题?在编写类时,OP询问了有关接口的信息。
幸运

0

由于不能继承静态方法。因此,将其放置在界面中没有用。接口基本上是所有订户都必须遵守的合同。在接口中放置静态方法将迫使订户实现它。现在,这与不能继承静态方法的事实矛盾。


静态方法总是被继承,但是不能被覆盖。
Akki

0

使用Java 8,接口现在可以具有静态方法。

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

接口不能具有实现的要求也得到了放松。接口现在可以声明“默认”方法实现,这与常规实现类似,但有一个例外:如果您既继承自接口的默认实现又继承自超类的常规实现,则超类的实现将始终优先。


我的天啊!我们有一个认真的程序员(和我,评论员)回答(和我,评论)10岁的问题。
Mohamed Anees

我没有注意到日期:)
Ishara

哈哈!没问题!
Mohamed Anees

-2

也许代码示例会有所帮助,我将使用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);
}

因此,现在您将看到接口是多么有用。

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

如果您已使薪水保持静态,则在遍历IPayable的accountsToPay中时,将无法确定应在BusinessAcount还是CustomerAccount上调用薪水。


仅仅因为静态方法在此示例中没有意义,并不表示它们在任何示例中都没有意义。在您的示例中,如果IPayable接口具有静态方法“ IncrementPayables”,该方法跟踪添加了多少应付款,那么这将是一个真实的用例。当然,可以始终使用抽象类,但这不是您要解决的。您的示例本身不会破坏接口中的静态方法。
Cruncher
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.