Конструктор в интерфейсе? - PullRequest
133 голосов
/ 10 мая 2010

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

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

Например,рассмотрим следующий класс сообщений:

public class MyMessage {

   public MyMessage(String receiver) {
      this.receiver = receiver;
   }

   private String receiver;

   public void send() {
      //some implementation for sending the mssage to the receiver
   }
}

Если определить интерфейс для этого класса, чтобы у меня было больше классов, реализующих интерфейс сообщений, я могу определить только метод send, а не конструктор.Итак, как я могу гарантировать, что каждая реализация этого класса действительно имеет набор получателей?Если я использую метод, подобный setReceiver(String receiver), я не могу быть уверен, что этот метод действительно вызывается.В конструкторе я смог это обеспечить.

Ответы [ 11 ]

122 голосов
/ 10 мая 2010

Взяв некоторые вещи, которые вы описали:

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

"Если определить интерфейс для этого класса, чтобы я мог иметь больше классы, которые реализуют интерфейс сообщения, я могу только определить Метод отправки, а не конструктор "

... эти требования как раз и предназначены для абстрактных классов .

68 голосов
/ 08 марта 2012

Проблема, возникающая при разрешении конструкторов в интерфейсах, связана с возможностью реализации нескольких интерфейсов одновременно. Когда класс реализует несколько интерфейсов, которые определяют разные конструкторы, класс должен будет реализовать несколько конструкторов, каждый из которых удовлетворяет только одному интерфейсу, но не другим. Будет невозможно построить объект, который вызывает каждый из этих конструкторов.

или в коде:

interface Named { Named(String name); }
interface HasList { HasList(List list); }

class A implements Named, HasList {

  /** implements Named constructor.
   * This constructor should not be used from outside, 
   * because List parameter is missing
   */
  public A(String name)  { 
    ...
  }

  /** implements HasList constructor.
   * This constructor should not be used from outside, 
   * because String parameter is missing
   */
  public A(List list) {
    ...
  }

  /** This is the constructor that we would actually 
   * need to satisfy both interfaces at the same time
   */ 
  public A(String name, List list) {
    this(name);
    // the next line is illegal; you can only call one other super constructor
    this(list); 
  }
}
10 голосов
/ 10 мая 2010

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

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

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

Подводя итог: это вызывает проблемы при вызове перегруженных методов из родительских конструкторов, процитировать mindprod :

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

4 голосов
/ 03 января 2018

Обходной путь, который вы можете попробовать, - определить метод getInstance() в вашем интерфейсе, чтобы разработчик знал, какие параметры необходимо обработать. Он не такой прочный, как абстрактный класс, но он обеспечивает большую гибкость, чем интерфейс.

Однако этот обходной путь требует от вас использования getInstance() для создания экземпляров всех объектов этого интерфейса.

1007 * Е.Г. *

public interface Module {
    Module getInstance(Receiver receiver);
}
4 голосов
/ 30 ноября 2015

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

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

2 голосов
/ 15 сентября 2017

Если вы хотите убедиться, что каждая реализация интерфейса содержит определенное поле, вам просто нужно добавить в интерфейс геттер для этого поля :

interface IMyMessage(){
    @NonNull String getReceiver();
}
  • не нарушит инкапсуляцию
  • он сообщит всем, кто использует ваш интерфейс, что объект Receiver должен быть каким-то образом передан классу (либо конструктором, либо установщиком)
2 голосов
/ 10 мая 2010

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

1 голос
/ 12 июля 2013

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

1 голос
/ 10 мая 2010

См. этот вопрос для почему (взято из комментариев).

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

0 голосов
/ 30 января 2018

Обычно конструкторы предназначены для инициализации нестатических членов определенного класса по отношению к объекту.

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

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

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

Вывод:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...