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



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



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


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

581   13  

13 ответов:

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

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

и

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

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

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

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

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

Math.add(2, 3);

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

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

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

теперь 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 и статическими методами resp.

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

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

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

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

}

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

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

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

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

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

возможно, пример кода поможет, я буду использовать 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);
}

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

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

если бы вы сделали pay static, при циклическом просмотре IPayable в accountsToPay не было бы никакого способа выяснить, должен ли он вызывать pay на BusinessAcount или CustomerAccount.

Comments

    Ничего не найдено.