Когда появилась Java 8, мы могли использовать методы по умолчанию в интерфейсах. Основным драйвером этой функции было расширение интерфейса при сохранении обратной совместимости для более старых версий интерфейса. Одним из примеров является введение метода stream()
в существующие классы Collection
.
Иногда, когда мы хотим ввести несколько методов по умолчанию, они могут использовать общую базу кода, и тогда было бы хорошо, если бы мы могли использовать частные методы в интерфейсе. Таким образом, мы можем повторно использовать наш код, а также предотвратить его доступ к классам, которые используют или реализуют интерфейс.
Но есть проблема. Частный и защищенный доступ в интерфейсах был отложен до Java 9. Итак, как мы можем использовать методы частного интерфейса в Java 8 сегодня?
Простое решение
Предположим, что у нас есть интерфейс Foo
с двумя методами; bar()
и bazz()
которые оба должны возвращать какой-то сложный для вычисления результат, исходящий из некоторого общего кода, подобного этому:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public interface Foo { default int bar() { return complicatedMethodWithManyLinesOfCode(); } default int bazz() { return complicatedMethodWithManyLinesOfCode() + 1 ; } // Will not work in Java 8 because interface methods cannot be private! private int complicatedMethodWithManyLinesOfCode() { // Actual code not shown... return 0 ; } } |
Вводя class
который содержит приватный метод, мы можем «спрятать» метод от внешнего доступа и почти уйти с приватными методами в интерфейсе Java 8. Это можно сделать так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
public interface Foo { default int bar() { return Hidden.complicatedMethodWithManyLinesOfCode(); } default int bazz() { return Hidden.complicatedMethodWithManyLinesOfCode() + 1 ; } class Hidden { private static int complicatedMethodWithManyLinesOfCode() { // Actual code not shown... return 0 ; } } } |
Метод Foo:complicatedMethodWithManyLinesOfCode
не виден извне классов или интерфейсов, но виден сам класс Hidden
. Однако методы и поля в Hidden
нельзя увидеть, если они закрытые.
Эта схема также может применяться для доступа к защищенному методу интерфейса. Технически, мы могли бы расширить класс Hidden
в интерфейсе, который также расширяет оригинальный интерфейс Foo
. Помните, что защищенные методы также видны в пакете, поэтому, если мы расширяем или используем интерфейс из одного и того же пакета, защищенные методы становятся видимыми (как и всегда).
Один недостаток заключается в том, что скрытые методы не могут получить доступ к другим методам в интерфейсе. Этот последний недостаток можно легко устранить, если скрытый статический метод получит параметр типа интерфейса. Предположим, что для метода complexMethodWithManyLinesOfCode требуется другое значение из интерфейса Foo
которое можно получить с помощью некоторого метода интерфейса с именем buzz()
, тогда он может выглядеть примерно так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public interface Foo { default int bar() { return Hidden.complicatedMethodWithManyLinesOfCode( this ); } default int bazz() { return Hidden.complicatedMethodWithManyLinesOfCode( this ) + 1 ; } int buzz(); class Hidden { private static int complicatedMethodWithManyLinesOfCode(Foo foo) { // Actual code not shown... return 0 + foo.buzz(); } } } |
Ссылка: | Java 8: объявите частные и защищенные методы в интерфейсах от нашего партнера JCG Пера Минборга из блога Minborg по Java Pot . |