Почему интерфейсы должны быть объявлены в Java?

Иногда у нас есть несколько классов, которые имеют некоторые методы с одинаковой сигнатурой, но не соответствуют объявленному интерфейсу Java. Например, оба JTextField и JButton (среди нескольких других в javax.swing. * ) имеют метод

public void addActionListener(ActionListener l)

Теперь, предположим, я хочу что-то сделать с объектами, у которых есть этот метод; тогда я хотел бы иметь интерфейс (или, возможно, определить его сам), например

  public interface CanAddActionListener {
      public void addActionListener(ActionListener l);
  }

, чтобы я мог написать:

  public void myMethod(CanAddActionListener aaa, ActionListener li) {
         aaa.addActionListener(li);
         ....

Но, к сожалению, я не могу:

     JButton button;
     ActionListener li;
     ...
     this.myMethod((CanAddActionListener)button,li);

Это приведение было бы незаконным. Компилятор знает , что JButton не является CanAddActionListener , потому что класс не объявлен для реализации этого интерфейса ... однако он " фактически "реализует его .

Иногда это доставляет неудобства - и сама Java изменила несколько основных классов, чтобы реализовать новый интерфейс, сделанный из старых методов (например, String реализует CharSequence ).

У меня вопрос: почему это так? Я понимаю полезность объявления того, что класс реализует интерфейс. Но в любом случае, глядя на мой пример, почему компилятор не может сделать вывод, что класс JButton "удовлетворяет" объявлению интерфейса (глядя внутрь него) и принять приведение? Это вопрос эффективности компилятора или есть более фундаментальные проблемы?

Мое резюме ответов : Это тот случай, когда Java могла сделать поправку на некоторую «структурную типизацию» (своего рода утиную типизацию - но проверено во время компиляции). Это не так. Помимо некоторых (непонятных для меня) трудностей с производительностью и реализацией, здесь есть гораздо более фундаментальная концепция: в Java объявление интерфейса (и вообще всего) не должно быть просто структурным ] (чтобы иметь методы с этими сигнатурами), но семантически : методы должны реализовывать какое-то конкретное поведение / намерение. Таким образом, класс, который структурно удовлетворяет некоторому интерфейсу (т. Е. Имеет методы с необходимыми сигнатурами), не обязательно удовлетворяет ему семантически (крайний пример: вспомните «интерфейсы маркеров» , у которых даже нет методов!). Следовательно, Java может утверждать, что класс реализует интерфейс, потому что (и только потому, что) он был явно объявлен. У других языков (Go, Scala) другая философия.

8
задан leonbloy 13 September 2012 в 18:07
поделиться