Очень хороший вопрос. Практически для всех остальных вещей в Java я нашел настоящую причину сделанного выбора, но для этого - нет. Для меня имеет смысл определить защищенный метод в интерфейсе, который позволяет другому классу внутри того же пакета использовать этот метод на реализующем объекте, не требуя раскрытия этого метода, который может не предназначаться для вызова кем-либо, кроме членов пакета для остального мира.
Маркус А.
4
@MarkusA. Но интерфейсы работают двусторонне, то есть они также могут быть реализованы классами вне текущего пакета (а затем, возможно, переданы в качестве аргументов методам внутри этого пакета). Как класс, находящийся вне текущего пакета, сможет реализовать «защищенные» методы некоторого общедоступного интерфейса?
MartinStettner
8
@MartinStettner: Не было бы. Вот в чем дело. Пакет может иметь несколько несвязанных классов, которые реализуют интерфейс, и хочет гарантировать любому коду, получающему ссылку на этот тип интерфейса, что он будет вести себя определенным образом. Такую гарантию можно было бы значительно усилить, если бы не допустить, чтобы внешний код утверждал, что реализует интерфейс, но при этом ведет себя вопреки его контракту.
если у интерфейса есть protectedметод, весь реализующий класс будет рассматриваться как подтип интерфейса. и все эти классы МОГУТ получить доступ к защищенным методам. Разве это не делает protectedключевое слово метода бесполезным? до тех пор, пока у нас нет способов ограничить, кто реализует это ключевое слово interface protected для метода, бесполезно. поправьте меня если я ошибаюсь!
амарнатх хариш
Ответы:
67
Потому что интерфейс должен означать «то, что вы можете видеть вне класса». Нет смысла добавлять непубличные методы.
Но почему бы не иметь функции, которые только члены того же пакета, что и интерфейс, «могут видеть извне класса»? У меня было несколько вариантов использования, когда я этого хотел.
Маркус А.
5
@MarkusA. Я понимаю, что это поздно, но тогда вы можете сделать полностью abstract class, что все interfaceесть, и указать любой доступ, который вы хотите. Допустим, это теряет преимущества нескольких реализаций, которые interfaceесть в Java, но честно установление контракта, который придерживается ограничений какого-либо другого пакета, будет непроверяемым и запутанным, так как вы практически не сможете получить доступ к методам своей собственной реализации вне этого пакета. .
pickypg
10
@pickypg Но если класс, реализующий интерфейс, уже расширяет другой класс, вы не можете заставить его расширять другой класс. Меня бы не смутил интерфейс, который используется только внутри пакета.
Flamma
24
@Raveline, -1. Возникает вопрос: «Почему интерфейс должен означать то, что вы можете видеть извне класса?» Java 8 уже допускает использование тела метода в интерфейсах, так почему бы не разрешить и защищенные абстрактные методы?
Pacerier
8
Я часто читаю это объяснение, но ИМХО оно неверное. Интерфейс - это своего рода «стандартный протокол обмена», независимо от того, идет ли речь об ООП, коммуникационном API или оборудовании. USB-порт на моем компьютере явно является публичным интерфейсом. Но контакты на моей материнской плате, которые находятся за корпусом с замком на ключ и открывают доступ к дополнительным портам USB, явно являются «защищенным» интерфейсом. Затем у нас есть микросхема BIOS, которая также является стандартизированным интерфейсом, но она никоим образом не публикуется, лишь немногие компании знают точные детали в частном порядке. Так что, конечно, интерфейсы могут иметь любую видимость! Почему не в ООП?
Foo Bar
55
Хотя часто цитируемая причина заключается в том, что «интерфейсы определяют публичные API», я думаю, что это чрезмерное упрощение. (И это тоже "пахнет" круговой логикой.)
Не было бы бессмысленным иметь интерфейсы, которые имеют несколько модификаторов доступа; например, частично общедоступный и частично ограниченный другими классами в том же пакете, что и интерфейс. Фактически, в некоторых случаях это может быть полезно, ИМО.
На самом деле, я думаю, что часть аргументов в пользу неявного публичного доступа к членам интерфейса заключается в том, что это упрощает язык Java :
Программистам проще иметь дело с неявно открытыми членами интерфейса. Сколько раз вы видели код (классы), в котором модификаторы доступа к методам выбирались как бы случайным образом? Многим «обычным» программистам трудно понять, как лучше всего управлять границами абстракции Java 1 . Добавление public / protected / package-private к интерфейсам еще больше усложняет им задачу.
Неявно открытые члены интерфейса упрощают спецификацию языка ... и, следовательно, задачу для разработчиков компилятора Java и людей, которые реализуют API Reflection.
Мнение о том, что «интерфейсы определяют общедоступные API», возможно, является следствием (или характеристикой) решения по упрощению языкового дизайна ... а не наоборот. Но на самом деле эти два направления мысли, вероятно, развивались в умах разработчиков Java параллельно.
Во всяком случае, официальный ответ на RFE в JDK-8179193 проясняет, что команда разработчиков Java решила 2, что разрешение protectedна использование интерфейсов добавляет сложности, но при этом мало пользы. Престижность @skomisa за обнаружение улик .
Свидетельства в RFE решают проблему. Это официальная причина, по которой это не было добавлено.
1 - Конечно, опытные программисты не испытывают затруднений с этими вещами и могут приветствовать более богатую палитру функций контроля доступа. Но что происходит, когда их код передается для обслуживания кому-то другому?
2 - Вы можете не согласиться с их решением или заявленной аргументацией, но это спорный вопрос.
Я должен сказать, что этот вопрос был повторно открыт после введения в Java 8 методов по умолчанию. Проект, над которым я сейчас работаю, похож на базовую природу интерфейса и предназначен для абстрагирования намерений от реализации.
Есть несколько случаев, когда я мог бы резко упростить свой код с помощью метода «защищенного по умолчанию». Оказывается, это на самом деле не работает, поскольку интерфейсы по-прежнему придерживаются логики Java 7. Обычный защищенный метод не имеет особого смысла по причинам, указанным выше; но если общедоступный метод по умолчанию требует низкоуровневого ресурса, который вряд ли изменится и может быть предоставлен защищенным методом, мне кажется, что наличие «защищенной по умолчанию» работы не только сохранит более чистый код, но и защитит будущих пользователей от случайные злоупотребления.
(Это, к сожалению, не меняет того факта, что мне все еще нужно чрезмерно усложнять свой код с помощью ненужных в противном случае абстрактов; но я намерен отправить запрос функции в Oracle.)
Согласен на 100%. Абстрактные классы были разумной альтернативой до введения методов по умолчанию. Однако ограничения, которые они накладывают на множественное наследование, означают, что они не идеальны. Интерфейсы с методами по умолчанию обычно являются лучшей альтернативой в мире> = JDK 1.8, но поскольку они не могут сохранять состояние, они полагаются на определение других абстрактных методов для раскрытия состояния, что означает, что состояние становится общедоступным, что не всегда вы хотите.
Отец Джереми Криг
10
Потому что интерфейсы определяют общедоступные API. Все, что защищено, - это внутренняя деталь, которая не принадлежит интерфейсу.
Вы можете использовать абстрактные классы с защищенными абстрактными методами, но интерфейсы ограничены общедоступными методами и общедоступными статическими конечными полями.
Вы заявили, что «потому что интерфейсы определяют публичные API». Так в чем причина того, что интерфейсы должны определять только publicAPI? Есть разница между «внутренними деталями» и «деталями реализации». protectedВ Java определенно не является внутренней деталью, поскольку теперь это общедоступный интерфейс, опубликованный для всех, кто может создать его подкласс, а это, по сути, весь мир.
Pacerier
1
Теперь это не так с методами по умолчанию в Java 8.
Марио Росси
@MarioRossi И это уже не так с методами частного интерфейса Java 9.
скомиса
7
Возможно, потому что это интерфейс , то есть он предназначен для того, чтобы сообщать клиентам, что они могут делать с экземплярами, а не указывать им, что они не могут делать.
Я не понимаю, почему интерфейс не может также сообщать подклассам, что они могут делать, не открывая эту реализацию внешнему миру. Это было дизайнерское решение, которое было принято в то время, когда абстрактные классы могли использоваться как прекрасная альтернатива. Но с появлением в интерфейсах методов по умолчанию абстрактные классы стали несовершенной альтернативой.
Отец Джереми Криг
6
Я твердо убежден, что интерфейсы должны допускать защищенные методы; кто сказал, что интерфейсы должны быть видны всем во всем мире? Что касается вашей точки зрения, что это может сбить с толку «обычных» (читай: некомпетентных) программистов: ООП в значительной степени касается правильного структурирования объектов, классов, пакетов и т. Д., Если программисту трудно делать все это должным образом, у него есть гораздо большая проблема. Java была создана для такого рода вещей.
В нескольких ответах здесь используются круговые аргументы, чтобы объяснить, почему методы интерфейса не могут быть защищены: это потому, что они должны быть общедоступными, поэтому, очевидно, они не могут быть защищены!
Защищенные методы в интерфейсах: совместное использование пакетов
Поскольку модификаторы в Java немного ограничены, способ совместного использования методов в пакетах ограничен общедоступными методами. Иногда делать метод общедоступным бывает опасно, но это необходимо из-за отсутствия соответствующих модификаторов. Мое решение преодолевает это ограничение.
Спецификация языка java в настоящее время не допускает использования модификатора protected для методов интерфейса. Мы можем воспользоваться этим фактом и использовать методы интерфейса protected для этой новой функции.
Если метод интерфейса помечен как защищенный, а интерфейс реализован классом в другом пакете, метод не обязательно должен быть общедоступным, но также может быть частным или, по крайней мере, защищенным пакетом. Метод является видимым, независимо от того, что класс объявляет, и дополнительно видимым в исходном пакете интерфейса (и подпакетах?).
Таким образом, мы могли использовать определенные методы в хорошо известных пакетах.
И это ответ на запрос на расширение, который был закрыт со статусом Won't fix:
Это предложение пытается решить проблему таким образом, чтобы добавить сложности и особые случаи с небольшой реальной прибылью. Типичный способ решить эту проблему - создать частный класс, реализующий общедоступный интерфейс. Методы реализации являются общедоступными, но находятся в частном классе, поэтому они остаются частными.
Альтернативный вариант, доступный начиная с Java 9, - сделать классы и методы общедоступными, но внутри модуля, который имеет квалифицированный экспорт в определенные «дружественные» модули, а не для широкой публики.
Итак, авторитетные выводы из этого отчета об ошибке:
Текущая ситуация не изменится; интерфейсы вряд ли когда-либо будут поддерживать protectedметоды.
Обоснование отказа от поддержки protectedметодов в интерфейсах состоит в том, что это « добавляет сложности и особые случаи для небольшого реального выигрыша ».
Начиная с Java 9 существует альтернативный подход для предоставления доступа к методам на уровне пакета. Используйте Систему модулей платформы Java (JPMS), чтобы « сделать классы и методы общедоступными, но в пределах модуля, который имеет квалифицированный экспорт в определенные« дружественные »модули вместо экспорта для широкой публики ».
Поскольку реализующий класс должен реализовывать ВСЕ методы, объявленные в вашем интерфейсе, что бы произошло, если бы реализующий класс находился в другом пакете?
Интерфейс Если вы хотите использовать что-то подобное, которое вы описали, продолжайте с абстрактными классами или вложенными интерфейсами.
Выдержка из стиля кода о переменных интерфейса, но все же применима к методам:
Переменные интерфейса неявно являются общедоступными, поскольку интерфейсы предназначены для предоставления интерфейса прикладного программирования (API), который полностью доступен программистам Java для ссылки и реализации в своих собственных приложениях. Поскольку интерфейс может использоваться в пакетах Java, отличных от их собственных, общедоступная видимость гарантирует, что программный код может получить доступ к переменной.
Объявление внутренних субинтерфейсов - хорошая практика, но технически вы не можете объявлять свои внутренние методы, как protectedв интерфейсе в Java.
Конечно, вы можете создать другой интерфейс для внутреннего использования, расширяющий публичный интерфейс:
Вы можете использовать InternalInterfaceинтерфейс внутри пакета, но вы должны принять любой подтип PublicInterface(в общедоступных методах):
package yourpackage;publicclassSomeClass{publicvoid someMethod(PublicInterface param){if(param instanceofInternalInterface){// run the optimized code}else{// run the general code}}}
Вне пакета пользователи могут использовать PublicInterfaceбез проблем.
Обычно в подобных ситуациях программисты создают абстрактные классы. Однако в этом случае мы теряем преимущества множественного наследования.
Пользователи могут использовать и вне пакета YourPublicInterface.Internal. Все в интерфейсе, включая вложенные интерфейсы, является общедоступным независимо от наличия или отсутствия publicключевого слова.
Грег Рулофс
1
Единственный сценарий, в котором это имеет смысл, - это когда вы хотите ограничить видимость одним и тем же пакетом. Все остальные варианты использования protectedне применимы. В частности, protectedметоды часто используются для предоставления доступа к некоторым деталям реализаций нижнего уровня для потомков. Но объявлять это в интерфейсе не имеет смысла, поскольку нет реализации более низкого уровня, которую можно было бы раскрыть.
И даже сценарий пакета - это не совсем то, о чем интерфейсы.
Для достижения того, что вы, вероятно, хотите, вам понадобятся два интерфейса: один для внутреннего использования, а другой вы предоставляете в общедоступном API. (Возможно, с внутренним, но не обязательно расширяющим публичный.) Или, как указывали другие, абстрактный суперкласс.
Абстрактный суперкласс может предотвратить наследование типов вне своего пакета. Кто-то, получив ссылку на такой тип суперкласса и доверяющий автору пакета, может быть уверен, что объект будет вести себя так, как заявлено. Если в пакете есть несколько классов, которые хотят предоставить некоторые общие функции, но не соответствуют надлежащей иерархии (например, одна реализация функций X и Y, одна Y и Z и одна X и Z), было бы полезно, если бы он мог раскрыть функциональность, использующая интерфейсы, при этом обещая, что экземпляры, на которые ссылаются типы интерфейсов, будут «подлинными».
supercat
0
Защищенные методы всегда доступны для подкласса, только если подкласс расширяет базовый класс.
В случае интерфейса подкласс никогда не расширяет интерфейс. Он реализует интерфейс.
Защищенные методы доступны через расширение, а не через реализацию .
Интерфейсы предназначены для предоставления методов внешнему миру . Таким образом, эти методы являются общедоступными по своей природе. Однако, если вы хотите ввести абстракцию в рамках одного и того же семейства классов, это возможно путем создания другого уровня абстракции между вашим интерфейсом и классом реализации, то есть абстрактным классом. Пример показан ниже.
publicinterfaceMyInterface{publicvoid publicMethod();// needs to be public}publicabstractclassMyAbstractClassimplementsMyInterface{@Overridepublicvoid publicMethod(){
protectedMethod();// you can call protected method here// do other stuff}protectedabstractvoid protectedMethod();// can be protected}publicclassMyClassextendsMyAbstractClass{@Overrideprotectedvoid protectedMethod(){// implement protected method here, without exposing it as public}}
Но частные методы, которые никто не увидит, разрешены в интерфейсах.
Alex78191
java имеет методы по умолчанию в интерфейсах, то есть интерфейс - это костыль для обхода множественного наследования абстрактных классов. Пусть тогда разрешено множественное наследование абстрактных классов. Конфликт методов по умолчанию не стал проблемой.
Alex78191
Ты прав. Начиная с Java 9, в интерфейсах разрешены частные методы. Они не могут быть абстрактными, и они реализуются и используются в интерфейсе, в основном, другими стандартными или статическими методами (если они сами статичны).
Стефанос
1
Этот ответ просто игнорирует заданный вопрос: почему интерфейсы не могут иметь защищенные методы? Защищенные методы по-прежнему будут «открывать методы для внешнего мира» , и утверждение, что «эти методы являются общедоступными по своей природе» , просто ложно. Они общедоступны, потому что язык был разработан таким образом, но он мог разрешать защищенные методы в интерфейсах. OP просто спрашивает, почему.
protected
метод, весь реализующий класс будет рассматриваться как подтип интерфейса. и все эти классы МОГУТ получить доступ к защищенным методам. Разве это не делаетprotected
ключевое слово метода бесполезным? до тех пор, пока у нас нет способов ограничить, кто реализует это ключевое слово interface protected для метода, бесполезно. поправьте меня если я ошибаюсь!Ответы:
Потому что интерфейс должен означать «то, что вы можете видеть вне класса». Нет смысла добавлять непубличные методы.
источник
abstract class
, что всеinterface
есть, и указать любой доступ, который вы хотите. Допустим, это теряет преимущества нескольких реализаций, которыеinterface
есть в Java, но честно установление контракта, который придерживается ограничений какого-либо другого пакета, будет непроверяемым и запутанным, так как вы практически не сможете получить доступ к методам своей собственной реализации вне этого пакета. .Хотя часто цитируемая причина заключается в том, что «интерфейсы определяют публичные API», я думаю, что это чрезмерное упрощение. (И это тоже "пахнет" круговой логикой.)
Не было бы бессмысленным иметь интерфейсы, которые имеют несколько модификаторов доступа; например, частично общедоступный и частично ограниченный другими классами в том же пакете, что и интерфейс. Фактически, в некоторых случаях это может быть полезно, ИМО.
На самом деле, я думаю, что часть аргументов в пользу неявного публичного доступа к членам интерфейса заключается в том, что это упрощает язык Java :
Программистам проще иметь дело с неявно открытыми членами интерфейса. Сколько раз вы видели код (классы), в котором модификаторы доступа к методам выбирались как бы случайным образом? Многим «обычным» программистам трудно понять, как лучше всего управлять границами абстракции Java 1 . Добавление public / protected / package-private к интерфейсам еще больше усложняет им задачу.
Неявно открытые члены интерфейса упрощают спецификацию языка ... и, следовательно, задачу для разработчиков компилятора Java и людей, которые реализуют API Reflection.
Мнение о том, что «интерфейсы определяют общедоступные API», возможно, является следствием (или характеристикой) решения по упрощению языкового дизайна ... а не наоборот. Но на самом деле эти два направления мысли, вероятно, развивались в умах разработчиков Java параллельно.
Во всяком случае, официальный ответ на RFE в JDK-8179193 проясняет, что команда разработчиков Java решила 2, что разрешение
protected
на использование интерфейсов добавляет сложности, но при этом мало пользы. Престижность @skomisa за обнаружение улик .Свидетельства в RFE решают проблему. Это официальная причина, по которой это не было добавлено.
1 - Конечно, опытные программисты не испытывают затруднений с этими вещами и могут приветствовать более богатую палитру функций контроля доступа. Но что происходит, когда их код передается для обслуживания кому-то другому?
2 - Вы можете не согласиться с их решением или заявленной аргументацией, но это спорный вопрос.
источник
Я должен сказать, что этот вопрос был повторно открыт после введения в Java 8 методов по умолчанию. Проект, над которым я сейчас работаю, похож на базовую природу интерфейса и предназначен для абстрагирования намерений от реализации.
Есть несколько случаев, когда я мог бы резко упростить свой код с помощью метода «защищенного по умолчанию». Оказывается, это на самом деле не работает, поскольку интерфейсы по-прежнему придерживаются логики Java 7. Обычный защищенный метод не имеет особого смысла по причинам, указанным выше; но если общедоступный метод по умолчанию требует низкоуровневого ресурса, который вряд ли изменится и может быть предоставлен защищенным методом, мне кажется, что наличие «защищенной по умолчанию» работы не только сохранит более чистый код, но и защитит будущих пользователей от случайные злоупотребления.
(Это, к сожалению, не меняет того факта, что мне все еще нужно чрезмерно усложнять свой код с помощью ненужных в противном случае абстрактов; но я намерен отправить запрос функции в Oracle.)
источник
Потому что интерфейсы определяют общедоступные API. Все, что защищено, - это внутренняя деталь, которая не принадлежит интерфейсу.
Вы можете использовать абстрактные классы с защищенными абстрактными методами, но интерфейсы ограничены общедоступными методами и общедоступными статическими конечными полями.
источник
public
API? Есть разница между «внутренними деталями» и «деталями реализации».protected
В Java определенно не является внутренней деталью, поскольку теперь это общедоступный интерфейс, опубликованный для всех, кто может создать его подкласс, а это, по сути, весь мир.Возможно, потому что это интерфейс , то есть он предназначен для того, чтобы сообщать клиентам, что они могут делать с экземплярами, а не указывать им, что они не могут делать.
источник
Я твердо убежден, что интерфейсы должны допускать защищенные методы; кто сказал, что интерфейсы должны быть видны всем во всем мире? Что касается вашей точки зрения, что это может сбить с толку «обычных» (читай: некомпетентных) программистов: ООП в значительной степени касается правильного структурирования объектов, классов, пакетов и т. Д., Если программисту трудно делать все это должным образом, у него есть гораздо большая проблема. Java была создана для такого рода вещей.
источник
В нескольких ответах здесь используются круговые аргументы, чтобы объяснить, почему методы интерфейса не могут быть защищены: это потому, что они должны быть общедоступными, поэтому, очевидно, они не могут быть защищены!
Это ничего не объясняет, но, к счастью, пару лет назад кто-то поднял запрос на улучшение защищенных методов в интерфейсах как ошибку JDK , которая проливает свет на проблему:
И это ответ на запрос на расширение, который был закрыт со статусом
Won't fix
:Итак, авторитетные выводы из этого отчета об ошибке:
protected
методы.protected
методов в интерфейсах состоит в том, что это « добавляет сложности и особые случаи для небольшого реального выигрыша ».источник
Поскольку реализующий класс должен реализовывать ВСЕ методы, объявленные в вашем интерфейсе, что бы произошло, если бы реализующий класс находился в другом пакете?
источник
Интерфейс Если вы хотите использовать что-то подобное, которое вы описали, продолжайте с абстрактными классами или вложенными интерфейсами.
Выдержка из стиля кода о переменных интерфейса, но все же применима к методам:
источник
Объявление внутренних субинтерфейсов - хорошая практика, но технически вы не можете объявлять свои внутренние методы, как
protected
в интерфейсе в Java.Конечно, вы можете создать другой интерфейс для внутреннего использования, расширяющий публичный интерфейс:
Вы можете использовать
InternalInterface
интерфейс внутри пакета, но вы должны принять любой подтипPublicInterface
(в общедоступных методах):Вне пакета пользователи могут использовать
PublicInterface
без проблем.Обычно в подобных ситуациях программисты создают абстрактные классы. Однако в этом случае мы теряем преимущества множественного наследования.
источник
YourPublicInterface.Internal
. Все в интерфейсе, включая вложенные интерфейсы, является общедоступным независимо от наличия или отсутствияpublic
ключевого слова.Единственный сценарий, в котором это имеет смысл, - это когда вы хотите ограничить видимость одним и тем же пакетом. Все остальные варианты использования
protected
не применимы. В частности,protected
методы часто используются для предоставления доступа к некоторым деталям реализаций нижнего уровня для потомков. Но объявлять это в интерфейсе не имеет смысла, поскольку нет реализации более низкого уровня, которую можно было бы раскрыть.И даже сценарий пакета - это не совсем то, о чем интерфейсы.
Для достижения того, что вы, вероятно, хотите, вам понадобятся два интерфейса: один для внутреннего использования, а другой вы предоставляете в общедоступном API. (Возможно, с внутренним, но не обязательно расширяющим публичный.) Или, как указывали другие, абстрактный суперкласс.
источник
Защищенные методы всегда доступны для подкласса, только если подкласс расширяет базовый класс.
В случае интерфейса подкласс никогда не расширяет интерфейс. Он реализует интерфейс.
Защищенные методы доступны через расширение, а не через реализацию .
источник
Интерфейсы предназначены для предоставления методов внешнему миру . Таким образом, эти методы являются общедоступными по своей природе. Однако, если вы хотите ввести абстракцию в рамках одного и того же семейства классов, это возможно путем создания другого уровня абстракции между вашим интерфейсом и классом реализации, то есть абстрактным классом. Пример показан ниже.
источник