Я знаю, что невозможно определить конструктор в интерфейсе. Но мне интересно, почему, потому что я думаю, что это может быть очень полезно.
Таким образом, вы можете быть уверены, что некоторые поля в классе определены для каждой реализации этого интерфейса.
Например, рассмотрим следующий класс сообщений:
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)
я не могу быть уверен, что этот метод действительно вызывается. В конструкторе я смог это обеспечить.
Ответы:
Взяв некоторые из вещей, которые вы описали:
... эти требования как раз и предназначены для абстрактных классов .
источник
Message
интерфейс, который определяетsend()
метод, и если Sebi желает предоставить «базовый» класс для реализацийMessage
интерфейса, то предоставьтеAbstractMessage
также и. Абстрактные классы не должны занимать место интерфейсов, никогда не пытался это предложить.Проблема, возникающая при разрешении конструкторов в интерфейсах, связана с возможностью реализации нескольких интерфейсов одновременно. Когда класс реализует несколько интерфейсов, которые определяют разные конструкторы, класс должен будет реализовывать несколько конструкторов, каждый из которых удовлетворяет только одному интерфейсу, но не другим. Будет невозможно построить объект, который вызывает каждый из этих конструкторов.
Или в коде:
источник
class A implements Named, HashList { A(){HashList(new list()); Named("name");} }
new Set<Fnord>()
бы можно было интерпретировать как «Дайте мне то, что я могу использовать какSet<Fnord>
»; если авторSet<T>
намеренHashSet<T>
стать готовой реализацией для вещей, в которых нет особой необходимости в чем-то еще, интерфейс, который затемnew Set<Fnord>()
может быть определен, может считаться синонимомnew HashSet<Fnord>()
. Для класса, реализующего несколько интерфейсов, не возникнет никаких проблем, посколькуnew InterfaceName()
он просто создаст класс, обозначенный интерфейсом .A(String,List)
конструктор может быть назначенным конструкторомA(String)
иA(List)
может быть вторичным, который его вызывает. Ваш код не контрпример, просто плохой.Интерфейс определяет контракт для API, то есть набора методов, с которыми согласны как разработчик, так и пользователь API. Интерфейс не имеет экземпляра реализации, следовательно, нет конструктора.
Описанный вами вариант использования похож на абстрактный класс, в котором конструктор вызывает метод абстрактного метода, который реализован в дочернем классе.
Присущая здесь проблема заключается в том, что пока выполняется базовый конструктор, дочерний объект еще не создан, и поэтому находится в непредсказуемом состоянии.
Подводя итог: это вызывает проблемы при вызове перегруженных методов из родительских конструкторов, чтобы процитировать mindprod :
источник
Обходной путь, который вы можете попробовать, - определить
getInstance()
метод в вашем интерфейсе, чтобы разработчик знал, какие параметры необходимо обработать. Он не такой прочный, как абстрактный класс, но он обеспечивает большую гибкость, чем интерфейс.Однако этот обходной путь требует, чтобы вы использовали
getInstance()
экземпляр всех объектов этого интерфейса.Например
источник
В интерфейсе есть только статические поля, которые не нужно инициализировать при создании объекта в подклассе, а метод интерфейса должен обеспечивать фактическую реализацию в подклассе. Так что в интерфейсе не требуется конструктор.
Вторая причина - во время создания объекта подкласса родительский конструктор называется. Но если будет реализовано более одного интерфейса, то при вызове конструктора интерфейса возникнет конфликт относительно того, какой конструктор интерфейса будет вызывать первым
источник
Если вы хотите убедиться, что каждая реализация интерфейса содержит определенное поле, вам просто нужно добавить в свой интерфейс метод получения для этого поля :
Receiver
объект должен быть каким-то образом передан классу (либо конструктором, либо установщиком)источник
Зависимости, на которые нет ссылок в методах интерфейса, следует рассматривать как подробности реализации, а не как то, что обеспечивает интерфейс. Конечно, могут быть исключения, но, как правило, вы должны определить свой интерфейс как ожидаемое поведение. Внутреннее состояние данной реализации не должно быть проблемой проектирования интерфейса.
источник
Посмотрите этот вопрос для почему (взято из комментариев).
Если вам действительно нужно сделать что-то подобное, вам может потребоваться абстрактный базовый класс, а не интерфейс.
источник
Это связано с тем, что интерфейсы не позволяют определять тело метода в нем. Но мы должны определить конструктор в том же классе, что и интерфейсы по умолчанию для абстрактных модификаторов для всех методов. Вот почему мы не можем определить конструктор в интерфейсах.
источник
Вот пример использования этой техники. В этом конкретном примере код выполняет вызов Firebase, используя макет,
MyCompletionListener
который представляет собой интерфейс, маскируемый как абстрактный класс, интерфейс с конструкторомисточник
private
модификатор доступа сinterface
?Обычно конструкторы предназначены для инициализации нестатических членов определенного класса относительно объекта.
Для интерфейса не создается объект, поскольку есть только объявленные методы, но не определенные методы. Почему мы не можем создать объект для объявленных методов? Создание объекта - это не что иное, как выделение некоторой памяти (в динамической памяти) для нестатических элементов.
JVM создаст память для членов, которые полностью разработаны и готовы к использованию. На основе этих членов JVM рассчитывает, сколько памяти им требуется, и создает память.
Что касается объявленных методов, JVM не может рассчитать, сколько памяти потребуется для этих объявленных методов, так как реализация будет в будущем, что не сделано к этому времени. поэтому создание объекта для интерфейса невозможно.
вывод:
без создания объекта нет возможности инициализировать нестатические члены с помощью конструктора. Именно поэтому конструктор не допускается внутри интерфейса (так как конструктор не используется внутри интерфейса).
источник