Почему Java не разрешает частные члены в интерфейсе? Есть ли какая-то особая причина?
Почему Java не разрешает частные члены в интерфейсе? Есть ли какая-то особая причина?
Ответы:
Из спецификации языка Java, (Контроль доступа) :
«Язык программирования Java предоставляет механизмы для управления доступом, чтобы предотвратить зависимость пользователей пакета или класса от ненужных деталей реализации этого пакета или класса».
Контроль доступа - это скрытие деталей реализации. Интерфейс не имеет реализации, которую нужно скрывать.
В Java 9 возможны частные методы в интерфейсах.
Команда компилятора javac рада объявить о доступности компилятором поддержки частных методов в интерфейсах, начиная с сборки JDK 9 b54.
Методы частного интерфейса являются частью Java 9 как часть JEP-213 . Поскольку интерфейсы в Java 8 могут иметь методы по умолчанию , частные методы позволяют нескольким методам по умолчанию использовать общий частный метод.
Начиная с Java 8, интерфейсы могут иметь методы по умолчанию, а с Java 9 интерфейс может иметь частные методы, к которым можно получить доступ только с помощью методов по умолчанию в том же интерфейсе.
Реализовать такой интерфейс было бы невозможно. Ответ на заданный мною вопрос убедительно свидетельствует о том, что было бы невозможно (без радикального изменения правил) реализовать интерфейс с частными методами - это оставляет открытым вопрос о том, почему защищенные и пакетные частные методы не разрешены.
class OuterClass
{
void run ( MyInterface x )
{
x . publicMethod ( ) ; // why not?
x . protectedMethod ( ) ; // why not?
x . packagePrivateMethod ( ) ; // why not?
x . privateMethod ( ) ; // why not?
}
interface MyInterface
{
public abstract void publicMethod ( ) ; // OK
protected abstract void protectedMethod ( ) ; // why not?
abstract void packagePrivateMethod ( ) ; // in interface default is public, but why not package private
private void privateMethod ( ) ; // impossible to implement
}
class MyImpl implements MyInterface
{
public void publicMethod ( ) { } // ok
protected void protectedMethod ( ) { } // no sweat
void packagePrivateMethod ( ) { } // no sweat
private void privateMethod ( ) { } // not happening
}
}
Приведенный ниже код должен достичь желаемого результата. Несмотря на то, что все методы являются общедоступными, только общедоступный метод фактически является общедоступным. Защищенный метод эффективно защищен. packagePrivateMethod фактически является packagePrivate. privateMethod фактически является частным.
class WorkAround
{
void run ( MyPrivateInterface x )
{
x . publicMethod ( ) ;
x . protectedMethod ( ) ;
x . packagePrivateMethod ( ) ;
x . privateMethod ( ) ;
}
public interface MyPublicInterface { void publicMethod ( ) ; }
protected interface MyProtectedInterface extends MyPublicInterface { void protectedMethod ( ) ; }
interface MyPackagePrivateInterface extends MyProtectedInterface { void packagePrivateMethod ( ) ; }
private interface MyPrivateInterface extends MyPackagePrivateInterface { void privateMethod ( ) ; }
}
Java разрешает частные методы в интерфейсе в Java 9 . Эти стандартные методы были введены в Java 8. Вполне возможно , что несколько методов по умолчанию хотят поделиться каким - то кодом, то этот код может быть перемещен в частный метод , не подвергая его внешний мир. Эта ошибка была исправлена, и начиная с JDK 9 build 54, компилятор возродил поддержку методов частного интерфейса.
public interface IData{
default void processData(int data) {
validate(data);
// do some work with it
}
default void consumeData(int data) {
validate(data);
// do some work with it
}
private void validate(int data) {
// validate data
}
}
Потому что они были бы бесполезны.
Не было бы возможности вызвать частный метод.
Частные члены - это деталь реализации. Интерфейс касается публичной роли, которую может взять на себя класс.
частные поля не были бы полностью бесполезными, поскольку другие поля и внутренние классы могли бы получить к ним доступ.
Однако частные методы не могли быть реализованы даже во вложенных классах, что делало их почти бесполезными. Вы можете прочитать их, используя отражение, но это скорее крайний случай.
Члены класса, объявленные закрытыми, не наследуются подклассами этого класса. Только члены класса, объявленные защищенными или общедоступными, наследуются подклассами, объявленными в пакете, отличном от того, в котором объявлен класс.
Источник
Итак, у вас нет рабочих методов в интерфейсе, которые могут работать с этим частным ненаследуемым полем. Тогда почему оно должно существовать?
Ага, не могу. Для всех, кто комментирует, почему этого не следует делать:
Представьте, что у меня есть класс A, который использует интерфейс I. Класс B расширяет класс A, поэтому также наследует все методы интерфейса в A.
Теперь представьте, что мне нужен частный метод в классе A, но я хочу, чтобы он был определен в контракте и для других классов (возможно, класс C, который не обязательно расширяет класс B или A).
Возможно, для метода «инициализации», который мне нужен для всех классов, использующих интерфейс I. Но, очевидно, я не хочу, чтобы метод инициализации был общедоступным ... поскольку его следует использовать только один раз или по мере необходимости, а не только потому, что вы хотите использовать его все волей-неволей.
Единственное решение - это обходной путь или просто принудительное использование метода init в самих классах без интерфейса.
Я не слишком понимаю причину, но все же иногда может пригодиться. Очевидно, Oracle соглашается, поскольку они разрешают методы частного интерфейса в JDK 9.
То, что я сделал, в любом случае для себя, заключалось в том, что я поместил простую логическую переменную, таким образом, метод интерфейса (который должен быть частным) может быть помечен как истинный (инициализированный = истинный) после того, как был установлен один раз. Затем при повторном вызове метод просто ничего не делает. Таким образом, метод интерфейса может быть реализован как общедоступный, но поскольку конструктор (моего класса) сначала вызывает метод, он устанавливает для переменной значение true, и поэтому он не может быть вызван снова.
В противном случае вам придется попробовать другой обходной путь, если вы хотите, чтобы его использовали только внутренние механизмы класса ... возможно, сам метод устанавливает и выключает флаг, когда он его использует. Когда флаг установлен в false, метод ничего не делает (это может быть, когда кто-то вызывает его извне класса). Однако, когда его вызывают собственные методы классов, они быстро устанавливают флаг в значение true, затем вызывают метод, а затем устанавливают флаг в значение false ??
В конце концов вроде немой. Возможно, сейчас лучше просто поместить частный класс в сам класс и вообще вырезать интерфейс.