代码之家  ›  专栏  ›  技术社区  ›  Henrik Paul

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

  •  148
  • Henrik Paul  · 技术社区  · 16 年前

    主题说明了其中的大部分——静态方法不能在接口中声明这一事实的原因是什么?

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

    上面的代码给出了以下错误(至少在Eclipse中):“接口方法itest.test()的非法修饰符;只允许使用public&abstract”。

    13 回复  |  直到 5 年前
        1
  •  85
  •   Community Egal    7 年前

    这里有几个问题要讨论。第一个问题是声明一个静态方法而不定义它。这就是

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

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

    第一个是不可能的,因为 Espo 注意:您不知道哪个实现类是正确的定义。

    爪哇 能够 允许后者;事实上,从Java 8开始,它确实如此!

        2
  •  44
  •   Espo    16 年前

    在接口中不能使用静态方法的原因在于Java解析静态引用的方式。当尝试执行静态方法时,Java不会麻烦寻找类的实例。这是因为静态方法不依赖实例,因此可以直接从类文件执行。考虑到接口中的所有方法都是抽象的,虚拟机必须查找接口的特定实现,以便找到静态方法背后的代码,以便执行该方法。这就与静态方法解析的工作方式相矛盾,并将在语言中引入不一致性。

        3
  •  18
  •   Kyle Cronin    16 年前

    我举个例子回答你的问题。假设我们有一个带有静态方法add的数学类。您可以这样调用此方法:

    Math.add(2, 3);
    

    如果Math是接口而不是类,则它不能有任何已定义的函数。因此,说一些类似数学的话。加(2,3)是没有意义的。

        4
  •  11
  •   Mnementh    15 年前

    其原因在于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()会发生什么?

        5
  •  7
  •   Ryan Farley    16 年前

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

        6
  •  5
  •   Ori Marko    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使它们成为默认方法和静态方法resp,那么默认情况下,接口中的方法仍然是公共抽象的。

        7
  •  4
  •   Community Egal    7 年前

    你的问题有一个非常好和简洁的答案 here . (我觉得这是一种非常直接的解释方式,我想从这里把它联系起来。)

        8
  •  3
  •   Lenik    11 年前

    接口中的静态方法可能在 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
  •  2
  •   Rob Cooper    16 年前

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

        10
  •  1
  •   Kumar Abhishek    8 年前

    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
  •  0
  •   Sankar    11 年前

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

    如果一个类的成员被声明为静态的,那么它可以与限制在该类中的类名一起使用,而不创建对象。

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

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

        12
  •  0
  •   ip_x    10 年前

    因为静态方法不能被继承。所以把它放在接口中没用。接口基本上是所有订户都必须遵守的合同。在接口中放置静态方法将强制订阅服务器实现它。这与静态方法不能被继承的事实相矛盾。

        13
  •  -2
  •   FlySwat    16 年前

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

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

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

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

    如果您将Pay设置为静态,则在通过iPayable的In AccountStopay循环时,将无法确定它是否应调用BusinessAccount或CustomerAccount上的Pay。