Интерфейсы Java 7 и конфликт имен

Я пишу код, в котором класс реализует два интерфейса, у которых два абстрактных метода с одинаковым именем и две константы с одинаковым идентификатором:

public class Test implements A,B {

  public void doStuff() {}

  public void make() {}

  public static void main(String[] args) {
    Test t=new Test();
    System.out.println(A.VALUE);
    System.out.println(B.VALUE);
    //System.out.println(Test.VALUE);
    //System.out.println(t.VALUE);
  }

}


interface A {              // implicitly abstract

  int VALUE=11;            // implicitly public static and final

  void doStuff();               // implicitly public and abstract

}


interface B {

  int VALUE=14;

  void make();

  void doStuff();

}

теперь я знаю, что с Java 7 мне не нужно беспокоиться о конфликте имен, поскольку это касается абстрактных методов (верно??): я просто предоставляю подходящую реализацию, и я хорош (все методы, которые разделяют одно и то же имя), поэтому у меня не возникает проблем, связанных с множественным наследованием, или "бриллиантов" (с этим я столкнусь, когда приду к Java 8, я полагаю).

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

Как это? это нормальное поведение? Я получаю сообщение об ошибке только при доступе к этим членам?

РЕДАКТИРОВАТЬ Я имею в виду, почему компилятор не предупреждает меня о неоднозначности, когда я пытаюсь реализовать интерфейсы?

5 ответов

теперь я знаю, что с Java 7 мне не нужно беспокоиться о конфликте имен, поскольку речь идет об абстрактных методах (правильно??)

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

Как это? это нормальное поведение? Я получаю сообщение об ошибке только при доступе к этим членам?

Да, конечно, это нормальное поведение; это в соответствии с правилами языка программирования Java (это не ошибка в компиляторе Java). Простое наследование константы от двух интерфейсов само по себе не вызывает двусмысленности, поэтому вы просто не получаете ошибку, когда просто пытаетесь это сделать.

Если вы попытаетесь использовать константу без квалификации, то компилятор не знает, какое из двух вы имеете в виду, поэтому он выдаст вам ошибку.

Вам нужно указать, из какого интерфейса вы хотите использовать константу:

interface A {
    int VALUE = 11;
}

interface B {
    int VALUE = 14;
}

public class Example implements A, B {
    public void method() {
        // Use A.VALUE instead of just VALUE
        System.out.println(A.VALUE);
    }
}

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

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

Спецификация Java позволяет вам определять наследование от разных интерфейсов с одинаковыми именами переменных. Таким образом, нет никакой двусмысленности, пока вы не получите доступ к ЗНАЧЕНИЮ. Затем вы пытаетесь получить к нему доступ, используя простое имя, компилятор не может решить, какую переменную он должен использовать, и только эта ситуация неоднозначна. Подробную информацию вы можете найти в спецификации Java https://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html

Цитата:

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

В вашем примере

interface A {              
  int VALUE=11;           
  void doStuff();               
}

interface B {
  int VALUE = 14;
  void make();
  void doStuff();
}

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

В приведенном выше примере интерфейсы A и B имеют открытые статические переменные конечного значения VALUE. И переменная интерфейса A назначается со значением 11, а интерфейс B назначается со значением 14.

Полная реализация для интерфейсов A и B - класс Test.

Здесь класс Test реализует A,B

По умолчанию все свойства и поведения доступны в классе Test. Но в этом случае переменная VALUE является статической, а остальные методы являются методами экземпляра. Поскольку область действия статических переменных находится на уровне класса, а распределение памяти для статических переменных отличается по сравнению с переменными экземпляра и методами экземпляра.

Следовательно, область действия различна (на уровне класса), так что в этом нет шансов на проблему с бриллиантами. Код компилируется нормально, а Out put - 11 12 соответственно.

При реализации компилятора интерфейса не знаю, где вы собираетесь их использовать, поэтому он не может предупредить. Рассмотрим этот сценарий. Есть три класса, которые наследуют эти интерфейсы... "открытый класс Test реализует A,B" "открытый класс Test1 реализует A" "открытый класс Test2 реализует B" В этом мы не можем пропустить переменную VALUE из любого интерфейса, потому что это обязательно в трех классах. Если из-за ошибки при создании интерфейсов вы не сможете достичь этого сценария.

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