Почему я не могу объявить статические методы в интерфейсе? - PullRequest
148 голосов
/ 22 августа 2008

В теме говорится больше всего - в чем причина того, что статические методы не могут быть объявлены в интерфейсе?

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

Приведенный выше код дает мне следующую ошибку (по крайней мере в Eclipse): «Недопустимый модификатор для метода интерфейса ITest.test (); разрешены только публичные и абстрактные».

Ответы [ 14 ]

85 голосов
/ 22 августа 2008

Здесь есть несколько проблем. Во-первых, это проблема объявления статического метода без его определения. Это разница между

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

и

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

Первое невозможно по причинам, которые Espo упоминает: вы не знаете, какой класс реализации является правильным определением.

Java может разрешить последнее; и фактически, начиная с Java 8, это так!

44 голосов
/ 22 августа 2008

Причина, по которой у вас не может быть статического метода в интерфейсе, заключается в том, как Java разрешает статические ссылки. Java не будет беспокоиться о поиске экземпляра класса при попытке выполнить статический метод. Это потому, что статические методы не зависят от экземпляра и, следовательно, могут выполняться прямо из файла класса. Учитывая, что все методы в интерфейсе являются абстрактными, ВМ должна была бы искать конкретную реализацию интерфейса, чтобы найти код, стоящий за статическим методом, чтобы он мог быть выполнен. Это противоречит принципу разрешения статических методов и может привести к несогласованности в языке.

18 голосов
/ 22 августа 2008

Я отвечу на ваш вопрос на примере. Предположим, у нас есть класс Math со статическим методом add. Вы бы назвали этот метод так:

Math.add(2, 3);

Если бы Math был интерфейсом вместо класса, он не мог бы иметь никаких определенных функций. Поэтому говорить что-то вроде Math.add (2, 3) бессмысленно.

11 голосов
/ 26 сентября 2008

Причина заключается в принципе дизайна, что 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 ()?

7 голосов
/ 22 августа 2008

Статические методы не являются методами экземпляра. Там нет контекста экземпляра, поэтому реализовывать его из интерфейса мало смысла.

5 голосов
/ 28 марта 2014

Теперь 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, чтобы сделать их Методами по умолчанию и Статическими методами соответственно.

4 голосов
/ 06 февраля 2009

Очень хороший и лаконичный ответ на ваш вопрос здесь . (Это показалось мне настолько простым и понятным способом объяснить это, что я хочу связать это отсюда.)

3 голосов
/ 17 сентября 2013

Кажется, что статический метод в интерфейсе может поддерживаться в 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 голосов
/ 22 августа 2008

Интерфейс используется для полиморфизма, который применяется к объектам, а не к типам. Поэтому (как уже отмечалось) нет смысла иметь статический интерфейсный элемент.

1 голос
/ 05 февраля 2016

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

}

...