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

Posted

技术标签:

【中文标题】为啥我不能在接口中声明静态方法?【英文标题】:Why can't I declare static methods in an interface?为什么我不能在接口中声明静态方法? 【发布时间】:2010-09-06 12:21:15 【问题描述】:

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

public interface ITest 
    public static String test();

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

【问题讨论】:

请不要接受 Espo 的回答,因为它有缺陷。接口有一个类文件,可以包含静态方法的实现(如果 Java 设计者允许这样做),因此解析静态方法的实现没有问题。它与其他静态类完全一样。 我有点同意“erickson”***.com/questions/512877/…987654321@的回答 这将在 Java 8 中提供。 @Vadorequest GIYF 但无论如何,check here 官方文档链接:Java SE tutorial & Java Language Specification 9.2 【参考方案1】:

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

public interface Foo 
  public static int bar();

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

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

Java 可以允许后者;事实上,从 Java 8 开始,它确实如此!

【讨论】:

是的 - 这是理想的而非技术性的。我想要它的原因是。可以在接口中具有静态“实现”方法,该方法仅引用接口中可以通过实现类轻松重用的其他“接口”方法。但是可以在接口中声明一个静态的,这样就可以让这样的东西存在于其中,例如 MyInterface.Impl.doIt(MyInterface i, Object[] args) ... 从 Java 8 开始,您可以在 interface 中定义 static 方法。方法必须是public @OlivierGrégoire ...而且它们没有被继承,这是关键。 很好的答案,虽然“大约相当于”ROFLMAO xD 我会说它更像“有点像”。【参考方案2】:

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

【讨论】:

这个解释不能解释问题。每个接口都有它自己的类文件,它可以包含静态方法。所以不需要查找特定的实现。 并非Java中的每个接口类型都在它自己的文件中,也不应该根据JLS。此外,JLS 并没有规定类必须始终存储在文件系统中,恰恰相反。 @Totophil:接口不能在单个 java 文件中,但编译后会有自己的类文件。这就是我写的。【参考方案3】:

我会用一个例子来回答你的问题。假设我们有一个带有静态方法 add 的 Math 类。你可以这样调用这个方法:

Math.add(2, 3);

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

【讨论】:

【参考方案4】:

原因在于设计原则,即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() 会发生什么?

【讨论】:

否决票的任何理由?一个解释性的评论会很好。 我不是反对者,但这不是对非静态方法也有效吗? 好的,这里有两种不同的可能性。可以实现或仅声明方法。我明白,必须实现静态方法。在这个意义上,我遇到了我的答案中提出的问题。如果你不这样做,你就会遇到 Espo 描述的问题——我不明白,因为我认为静态方法会被实现。你也不能因为这个原因声明一个静态抽象方法,试试看,编译器会报错。 好吧,忘记实现部分。问题是为什么我们不能宣布。是的,编译器会抱怨,为什么这是问题所在。我认为你没有回答。 如果接口A 包含int x(int z); 和接口B 包含string x(int x);,情况会怎样?接口C中x(3)是什么意思?【参考方案5】:

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

【讨论】:

【参考方案6】:

现在 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 将它们分别设为默认方法和静态方法,则接口中的方法默认仍然是公共抽象的。

【讨论】:

【参考方案7】:

您的问题here 有一个非常简洁的答案。 (它以一种非常直接的方式解释它让我印象深刻,我想从这里链接它。)

【讨论】:

这不是问题的答案,充其量应该是评论。【参考方案8】:

看来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...的形式访问,这样就可以摆脱歧义问题。

【讨论】:

【参考方案9】:

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

【讨论】:

在一些反思性的语境中似乎是有道理的【参考方案10】:

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);

【讨论】:

【参考方案11】:

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

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

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

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

【讨论】:

这如何回答这个问题?当你写关于类的时候,OP 询问了接口。【参考方案12】:

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

【讨论】:

静态方法总是被继承,但不能被覆盖。【参考方案13】:

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

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

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

【讨论】:

天啊!我们有一个认真的程序员(和我,评论者)回答(和我,评论)10 年前的问题。 我没有注意到日期:) 哈哈!没问题!【参考方案14】:

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

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

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

如果您已将 pay 设为静态,则当循环通过 accountsToPay 中的 IPayable 时,将无法确定它是否应该在 BusinessAcount 或 CustomerAccount 上调用 pay。

【讨论】:

仅仅因为静态方法在这个例子中没有意义,并不意味着它们在任何例子中都没有意义。在您的示例中,如果 IPayable 接口具有静态方法“IncrementPayables”来跟踪添加了多少应付账款,这将是一个真实的用例。当然,总是可以使用抽象类,但这不是您要解决的问题。您的示例本身不会破坏接口中的静态方法。

以上是关于为啥我不能在接口中声明静态方法?的主要内容,如果未能解决你的问题,请参考以下文章

为什么接口方法不能“静态”和“最终”?

为啥我不能在 C# 中使用抽象静态方法?

为啥我不能只用前向声明 C++ 声明一个类的静态成员?

为啥静态成员函数只能在类定义中声明为静态,而不能在其自己的定义中声明?

java:在java中为啥静态变量没有this引用?

为啥我们不能在(非静态)内部类(Java 16 之前)中使用静态方法?