Почему я не могу объявлять статические методы в интерфейсе?
В этом разделе рассказывается большинство из них - в чем причина того, что статические методы не могут быть объявлены в интерфейсе?
public interface ITest {
public static String test();
}
Приведенный выше код дает мне следующую ошибку (по крайней мере, в Eclipse): "Недопустимый модификатор для метода интерфейса ITest.test(), разрешены только публичные и абстрактные".
Ответы
Ответ 1
Здесь есть несколько проблем. Во-первых, это проблема объявления статического метода без его определения. В этом разница между
public interface Foo {
public static int bar();
}
и
public interface Foo {
public static int bar() {
...
}
}
Первое невозможно по причинам, описанным в Espo: вы не знаете, какой класс реализации является правильным.
Java может разрешить последнее; и фактически, начиная с Java 8, он делает это!
Ответ 2
Причина, по которой у вас не может быть статический метод в интерфейсе, заключается в том, как Java разрешает статические ссылки. Java не захочет искать экземпляр класса при попытке выполнить статический метод. Это связано с тем, что статические методы не зависят от экземпляра и поэтому могут выполняться непосредственно из файла класса. Учитывая, что все методы в интерфейсе абстрактны, виртуальной машине придется искать конкретную реализацию интерфейса, чтобы найти код, стоящий за статическим методом, чтобы он мог быть выполнен. Это противоречит тому, как работает статическое разрешение метода, и вводит несогласованность в языке.
Ответ 3
Я отвечу на ваш вопрос с примера. Предположим, что у нас был класс Math со статическим методом add. Вы бы назвали этот метод следующим:
Math.add(2, 3);
Если Math является интерфейсом вместо класса, он не может иметь никаких определенных функций. Как таковое, говорить что-то вроде Math.add(2, 3) не имеет смысла.
Ответ 4
Причина заключается в принципе дизайна, что 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
Статические методы не являются методами экземпляра. Нет контекста экземпляра, поэтому его реализация с интерфейсом не имеет смысла.
Ответ 6
Теперь 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, чтобы использовать их методы Defender и статические методы.
Ответ 7
Здесь очень приятный и краткий ответ на ваш вопрос здесь. (Это показалось мне таким простым способом объяснить это, что я хочу связать его здесь.)
Ответ 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...
, тогда вы можете избавиться от неоднозначной проблемы.
Ответ 9
Интерфейс используется для полиморфизма, который применяется к объектам, а не к типам. Поэтому (как уже отмечалось) нет смысла иметь статический член интерфейса.
Ответ 10
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
Нелегальная комбинация модификаторов: статическая и абстрактная
Если член класса объявлен как статический, его можно использовать с его именем класса, которое ограничено этим классом, без создания объекта.
Если член класса объявлен как абстрактный, вам нужно объявить класс абстрактным, и вам необходимо обеспечить реализацию абстрактного элемента в его унаследованном классе (подкласс).
Вам нужно предоставить реализацию абстрактному члену класса в подклассе, где вы собираетесь изменить поведение статического метода, также объявленного как абстрактный, который ограничен базовым классом, что неверно
Ответ 12
Так как статические методы не могут быть унаследованы. Поэтому не нужно размещать его в интерфейсе. Интерфейс - это в основном контракт, за которым должны следовать все его подписчики. Размещение статического метода в интерфейсе заставит подписчиков реализовать его. который теперь становится противоречащим тому, что статические методы не могут быть унаследованы.
Ответ 13
Возможно, пример кода поможет, я собираюсь использовать С#, но вы должны иметь возможность следовать.
Давайте сделаем вид, что у нас есть интерфейс под названием 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 в аккаунтахToPay, не будет никакого способа выяснить, следует ли ему вызывать оплату по BusinessAcount или CustomerAccount.