Почему я не могу объявить статические методы в интерфейсе?

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

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

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

Пожалуйста, не принимайте ответ Эспо, поскольку он ошибочен. Интерфейс имеет файл класса, который может содержать реализацию статического метода (если Java-дизайнер допускает это), поэтому нет проблем с разрешением реализации статического метода. Он работает точно так же, как и с другими статическими классами.

Mnementh 26.09.2008 12:51

я вроде как согласен с ответом "erickson" stackoverflow.com/questions/512877/…

Maverick 11.11.2013 15:59

Это будет доступно в Java 8, кстати.

m0skit0 29.12.2013 18:11

@ m0skit0 У вас есть ссылка на это? Звучит круто.

Vadorequest 04.02.2014 01:19

@Vadorequest GIYF, но все равно проверьте здесь

m0skit0 05.02.2014 15:47

Да конечно я мог бы найти это;) Но когда ты говоришь что-то подобное, всегда лучше дать ссылку! Спасибо.

Vadorequest 05.02.2014 16:35

Ссылки из официальной документации: Руководство по Java SE & Спецификация языка Java 9.2

LoganMzz 22.04.2015 11:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
152
7
103 725
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

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

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

Math.add(2, 3);

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

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

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

Mnementh 26.09.2008 12:38

Не каждый тип интерфейса в Java находится в собственном файле и не должен соответствовать JLS. Кроме того, JLS не предусматривает, что классы всегда должны храниться в файловой системе, как раз наоборот.

Vlad Gudim 06.02.2009 15:22

@Totophil: Интерфейсы не должны находиться в одном java-файле, но после компиляции у него будет собственный класс-файл. Вот что я написал.

Mnementh 07.01.2011 19:00

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

В некоторых рефлексивных контекстах это почти имеет смысл, хотя

Cruncher 27.08.2013 19:07

Возможно, поможет пример кода, я собираюсь использовать 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 не было бы способа выяснить, должен ли он вызывать pay на BusinessAcount или CustomerAccount.

Тот факт, что статические методы не имеют смысла в ЭТОМ примере, не означает, что они не имеют смысла в ЛЮБОМ примере. В вашем примере, если бы интерфейс IPayable имел статический метод «IncrementPayables», который отслеживал, сколько кредиторских задолженностей было добавлено, это был бы реальный вариант использования. Конечно, всегда можно использовать абстрактный класс, но это не то, к чему вы обращались. Ваш пример сам по себе не подрывает статические методы в интерфейсах.

Cruncher 27.08.2013 19:10
Ответ принят как подходящий

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

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) {...}

peterk 21.06.2013 19:02

Начиная с Java 8, вы можете определять методы static в interface. Методы должны быть public.

Olivier Grégoire 25.06.2014 16:46

@ OlivierGrégoire ... и они не передаются по наследству, и это главное.

William F. Jameson 07.08.2014 01:12

Хороший ответ, хотя «примерно эквивалентный» ROFLMAO xD Я бы сказал, скорее, «чем-то напоминает».

Timo 18.05.2015 15:51

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

Есть ли причина для отрицательного голоса? Было бы неплохо дать поясняющий комментарий.

Mnementh 07.01.2011 19:01

Я не голосующий против, но разве это не верно и для нестатических методов?

nawfal 05.10.2012 19:36

Хорошо, вот две разные возможности. Метод может быть реализован или только объявлен. Я понял, что статический метод надо реализовать. В этом смысле я сталкиваюсь с проблемой, представленной в моем ответе. Если вы этого не сделаете, вы столкнетесь с проблемой, описанной Эспо, и которую я не понял, потому что предполагал, что статический метод будет реализован. По этой причине вы также не можете объявить статический абстрактный метод, попробуйте, компилятор пожалуется.

Mnementh 06.10.2012 00:42

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

nawfal 06.10.2012 00:53

Что может быть хуже, чем если бы интерфейс A содержал int x(int z);, а интерфейс B содержал string x(int x);? Что означает x(3) в интерфейсе C?

supercat 01.02.2013 12:26

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

Stefan 21.03.2013 21:00

Но статические поля разрешены. Я мог бы определить A.x и B.x на ваших интерфейсах. И в этом случае попытка сослаться на (неоднозначный) C.x вызывает ошибку времени компиляции. Нельзя ли сделать то же самое для статических методов? (Это план в Java 8?)

Partly Cloudy 24.08.2013 03:41

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

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

CubeJockey 06.05.2016 17:02

Кажется, что статический метод в интерфейсе может поддерживаться в 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..., тогда вы можете избавиться от неоднозначной проблемы.

Незаконное сочетание модификаторов: статического и абстрактного

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

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

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

Как это отвечает на вопрос? OP спросил об интерфейсе, пока вы писали о классе.

Lucky 19.09.2016 16:16

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

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

Akki 27.02.2016 20:48

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

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

}

With Java 8, interfaces can now have static methods.

Например, в Comparator есть статический метод naturalOrder ().

Также было ослаблено требование о том, что интерфейсы не могут иметь реализации. Интерфейсы теперь могут объявлять реализации методов «по умолчанию», которые похожи на обычные реализации с одним исключением: если вы наследуете как реализацию по умолчанию от интерфейса, так и обычную реализацию от суперкласса, реализация суперкласса всегда будет иметь приоритет.

МОЙ БОГ! У нас есть серьезный программист (и я, комментатор), отвечающий (и я, комментирующий) на вопрос 10-летней давности.

Mohamed Anees A 21.02.2019 15:11

Дату не заметил :)

Ishara 22.02.2019 06:54

Ха-ха! Без проблем!

Mohamed Anees A 22.02.2019 07:48

Другие вопросы по теме