Тема говорит большую часть этого - в чем причина того, что статические методы не могут быть объявлены в интерфейсе?
public interface ITest {
public static String test();
}
Приведенный выше код дает мне следующую ошибку (по крайней мере, в Eclipse): «Недопустимый модификатор для метода интерфейса ITest.test (); разрешены только общедоступные и абстрактные».
я вроде как согласен с ответом "erickson" stackoverflow.com/questions/512877/…
Это будет доступно в Java 8, кстати.
@ m0skit0 У вас есть ссылка на это? Звучит круто.
@Vadorequest GIYF, но все равно проверьте здесь
Да конечно я мог бы найти это;) Но когда ты говоришь что-то подобное, всегда лучше дать ссылку! Спасибо.
Ссылки из официальной документации: Руководство по Java SE & Спецификация языка Java 9.2




Статические методы не являются методами экземпляра. Контекст экземпляра отсутствует, поэтому реализовывать его из интерфейса не имеет особого смысла.
Я отвечу на ваш вопрос примером. Предположим, у нас есть класс Math со статическим методом add. Вы бы назвали этот метод так:
Math.add(2, 3);
Если бы Math был интерфейсом, а не классом, у него не могло бы быть определенных функций. Таким образом, говорить что-то вроде Math.add (2, 3) не имеет смысла.
Причина, по которой у вас не может быть статического метода в интерфейсе, заключается в том, как Java разрешает статические ссылки. Java не будет искать экземпляр класса при попытке выполнить статический метод. Это связано с тем, что статические методы не зависят от экземпляра и, следовательно, могут выполняться прямо из файла класса. Учитывая, что все методы в интерфейсе являются абстрактными, виртуальной машине придется искать конкретную реализацию интерфейса, чтобы найти код, стоящий за статическим методом, чтобы его можно было выполнить. Тогда это противоречит тому, как работает разрешение статических методов, и внесет несогласованность в язык.
Это объяснение не объясняет проблемы. У каждого интерфейса есть свой класс-файл, он может содержать статический метод. Таким образом, поиск конкретной реализации не потребуется.
Не каждый тип интерфейса в Java находится в собственном файле и не должен соответствовать JLS. Кроме того, JLS не предусматривает, что классы всегда должны храниться в файловой системе, как раз наоборот.
@Totophil: Интерфейсы не должны находиться в одном java-файле, но после компиляции у него будет собственный класс-файл. Вот что я написал.
Интерфейс используется для полиморфизма, который применяется к объектам, а не к типам. Поэтому (как уже отмечалось) нет смысла иметь статический член интерфейса.
В некоторых рефлексивных контекстах это почти имеет смысл, хотя
Возможно, поможет пример кода, я собираюсь использовать 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», который отслеживал, сколько кредиторских задолженностей было добавлено, это был бы реальный вариант использования. Конечно, всегда можно использовать абстрактный класс, но это не то, к чему вы обращались. Ваш пример сам по себе не подрывает статические методы в интерфейсах.
Здесь есть несколько проблем. Первый - это проблема объявления статического метода без его определения. В этом разница между
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, вы можете определять методы static в interface. Методы должны быть public.
@ OlivierGrégoire ... и они не передаются по наследству, и это главное.
Хороший ответ, хотя «примерно эквивалентный» ROFLMAO xD Я бы сказал, скорее, «чем-то напоминает».
Причина кроется в принципе дизайна, что 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 ()?
Есть ли причина для отрицательного голоса? Было бы неплохо дать поясняющий комментарий.
Я не голосующий против, но разве это не верно и для нестатических методов?
Хорошо, вот две разные возможности. Метод может быть реализован или только объявлен. Я понял, что статический метод надо реализовать. В этом смысле я сталкиваюсь с проблемой, представленной в моем ответе. Если вы этого не сделаете, вы столкнетесь с проблемой, описанной Эспо, и которую я не понял, потому что предполагал, что статический метод будет реализован. По этой причине вы также не можете объявить статический абстрактный метод, попробуйте, компилятор пожалуется.
Хорошо, забудьте про реализацию. вопрос в том, почему мы не можем заявить. да, компилятор будет жаловаться, и в этом вопрос. на который я не думаю, что вы ответили.
Что может быть хуже, чем если бы интерфейс A содержал int x(int z);, а интерфейс B содержал string x(int x);? Что означает x(3) в интерфейсе C?
Я не уверен, что согласен с точной формулировкой, но ответ имеет смысл в объяснении, почему статические методы в интерфейсе не должны быть разрешены.
Но статические поля разрешены. Я мог бы определить A.x и B.x на ваших интерфейсах. И в этом случае попытка сослаться на (неоднозначный) C.x вызывает ошибку времени компиляции. Нельзя ли сделать то же самое для статических методов? (Это план в Java 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..., тогда вы можете избавиться от неоднозначной проблемы.
Незаконное сочетание модификаторов: статического и абстрактного
Если член класса объявлен как статический, его можно использовать с именем класса, которое ограничено этим классом, без создания объекта.
Если член класса объявлен как абстрактный, вам необходимо объявить класс как абстрактный, и вам необходимо предоставить реализацию абстрактного члена в его унаследованном классе (подклассе).
Вам необходимо предоставить реализацию абстрактному члену класса в подклассе, где вы собираетесь изменить поведение статического метода, также объявленного как абстрактный, который ограничен базовым классом, что неверно
Как это отвечает на вопрос? OP спросил об интерфейсе, пока вы писали о классе.
Поскольку статические методы не могут быть унаследованы. Так что нет смысла размещать его в интерфейсе. Интерфейс - это, по сути, договор, которому должны следовать все его подписчики. Размещение статического метода в интерфейсе заставит подписчиков реализовать его. что теперь противоречит тому факту, что статические методы не могут быть унаследованы.
статические методы всегда наследуются, но их нельзя переопределить.
Теперь 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-летней давности.
Дату не заметил :)
Ха-ха! Без проблем!
Пожалуйста, не принимайте ответ Эспо, поскольку он ошибочен. Интерфейс имеет файл класса, который может содержать реализацию статического метода (если Java-дизайнер допускает это), поэтому нет проблем с разрешением реализации статического метода. Он работает точно так же, как и с другими статическими классами.