2008-08-22 7 views
142

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

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

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

+2

Пожалуйста unaccept ответ Эспоо, поскольку она имеет недостатки. Интерфейс имеет класс-файл, который может содержать реализацию статического метода (если Java-конструктор допустил бы это), поэтому нет проблем при разрешении реализации статического метода. Он работает точно так же, как и с другими статическими классами. – Mnementh 2008-09-26 08:51:19

+0

Я согласен с ответом, данным «erickson» http://stackoverflow.com/questions/512877/why-cant-i-define-a-static-method-in-a-java-interface – Maverick 2013-11-11 11:59:42

+8

Это будут доступны на Java 8 бит. – m0skit0 2013-12-29 14:11:06

ответ

78

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

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

и

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

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

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

7

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

20

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

Math.add(2, 3); 

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

40

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

+3

Это объяснение не объясняет проблему. Каждый интерфейс имеет собственный класс-файл, он может содержать статический метод. Поэтому никакого поиска для конкретной реализации не потребуется. – Mnementh 2008-09-26 08:38:53

+0

Не каждый тип интерфейса в Java находится внутри его собственного файла, а также не должен соответствовать JLS. Кроме того, JLS не предусматривает, что классы должны всегда храниться с файловой системой, наоборот. – 2009-02-06 12:22:27

2

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

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

Теперь, w e хотите оплатить все эти счета в размере 50 долларов США:

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

Итак, теперь вы видите, как интерфейсы невероятно полезны.

Используются только для экземпляров объектов. Не на статических классах.

Если вы сделали статическую зарплату, когда запустили IPayable в аккаунтахToPay, не было бы возможности выяснить, следует ли вызывать оплату по BusinessAcount или CustomerAccount.

11

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

4

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

2

Похоже, что статический метод в интерфейсе может поддерживаться в 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

Нелегальная комбинации модификаторов: статические и абстрактные

Если член класса объявлен как статический, он может быть использован с именем класса, который прикован к этому классу, без создания объекта.

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

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

0

Поскольку статические методы не могут быть унаследованы. Поэтому не нужно размещать его в интерфейсе. Интерфейс - это в основном контракт, за которым должны следовать все его подписчики. Размещение статического метода в интерфейсе заставит подписчиков реализовать его. который теперь становится противоречащим тому, что статические методы не могут быть унаследованы.

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 
    } 
} 

Примечание: Методы в интерфейсе по-прежнему общественности абстрактные по умолчанию, если мы не будем явно использовать ключевые слова по умолчанию/статический, чтобы сделать их методы Защитнику и статические методы соответственно.

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

}