Я только недавно заметил, что есть возможность иметь статические методы в интерфейсах. Как и в случае статических полей интерфейса, есть интересное поведение: они не наследуются.
Я не уверен, что это полезно в реальных интерфейсах, которые должны быть реализованы. Тем не менее, он позволяет программисту создавать интерфейсы, которые являются просто оболочками для статических вещей, как, например, служебные классы.
Простой пример - просто конверт для глобальных констант. По сравнению с классом, вы можете легко заметить отсутствующий шаблон public static final
как предполагаемый (что делает его менее многословным).
public interface Constants {
String LOG_MESSAGE_FAILURE = "I took an arrow to the knee.";
int DEFAULT_TIMEOUT_MS = 30;
}
Вы также можете сделать что-то более сложное, например псевдо-перечисление ключей конфигурации.
public interface ConfigKeys {
static createValues(ConfigKey<?>... values) {
return Collections.unmodifiableSet(new HashSet(Arrays.asList(values)));
}
static ConfigKey<T> key(Class<T> clazz) {
return new ConfigKey<>(clazz);
}
class ConfigKey<T> {
private final Class<T> type;
private ConfigKey(Class<T> type) {
this.type = type;
}
private Class<T> getType() {
return type;
}
}
}
import static ConfigKeys.*;
public interface MyAppConfigKeys {
ConfigKey<Boolean> TEST_MODE = key(Boolean.class);
ConfigKey<String> COMPANY_NAME = key(String.class);
Set<ConfigKey<?>> VALUES = createValues(TEST_MODE, COMPANY_VALUE);
static values() {
return VALUES;
}
}
Вы также можете создать некоторую утилиту "класс" таким образом. Однако в утилитах часто полезно использовать закрытые или защищенные вспомогательные методы, что не совсем возможно в классах.
Я считаю, что это хорошая новая функция, и особенно тот факт, что статические члены не наследуются, является интересной концепцией, которая была представлена только для интерфейсов.
Интересно, можете ли вы считать это хорошей практикой? Хотя стиль кода и лучшие практики не являются аксиоматичными и есть место для мнений, я думаю, что обычно существуют веские причины, поддерживающие мнение.
Меня больше интересуют причины (не) использовать шаблоны, подобные этим двум.
Обратите внимание, что я не собираюсь реализовывать эти интерфейсы. Они просто конверт для их статического содержания. Я только намерен использовать константы или методы и, возможно, использовать статический импорт.
default
методах. Я говорю оstatic
методах и областях. Они не наследуются, поэтому они не нарушают множественное наследование.Ответы:
Помещение констант в интерфейсы называется,
Constant Interface Antipattern
поскольку константы часто являются просто деталями реализации. Дальнейшие недостатки описаны в статье в Википедии об интерфейсе Constant .Действительно, в документе Java говорится, что статические методы могут упростить организацию вспомогательных методов, например, при вызове вспомогательных методов из методов по умолчанию.
источник
Как указано в вопросе, интерфейс не предназначен для реализации (или создания экземпляра). Таким образом, мы могли бы сравнить его с классом, который имеет приватный конструктор:
super()
вызова, но интерфейс может быть "реализован"new MyInterface() {};
Это сравнение в пользу класса, поскольку оно дает больше контроля. Тем не менее, класс также не предназначен для хранения статического содержимого, вы ожидаете, что у него будут экземпляры. Ну нет идеального варианта.
Есть также странная вещь в наследовании от «статического интерфейса»:
Это может быть причиной считать это плохим паттерном и продолжать использовать статические классы для этих случаев. Тем не менее, для кого-то, кто пристрастился к синтаксическому сахару, он все еще может быть заманчивым даже с недостатками.
источник
Как и @MarkusPscheidt, эта идея по сути является расширением антипаттерна Constant Interface . Этот подход первоначально широко использовался, чтобы позволить одному набору констант наследоваться многими разнородными классами. Причиной того, что это считается антипаттерном, стало то, что проблемы возникли при использовании этого подхода в реальных проектах. Я не вижу оснований думать, что эти проблемы будут касаться только констант.
Вероятно, что еще более важно, действительно нет необходимости делать это. Вместо этого используйте статический импорт и четко указывайте, что вы импортируете и откуда.
источник
interface ColorFilter {Image applyGradient(int colorSpace, int width, byte[] pixels); }
. Я могу себе представить , чтобы там быть некоторые различные константыRGB
,RGBA
,CMYK
,GREYSCALE
, иINDEXED
т.д.Я бы сказал, если вам интересно, как правильно использовать новую функцию, взгляните на код в JDK. Методы по умолчанию на интерфейсах очень широко используются и их легко найти, но статические методы на интерфейсах кажутся очень редкими. Некоторые примеры включают
java.time.chrono.Chronology
,java.util.Comparator
,java.util.Map
и довольно много интерфейсов вjava.util.function
иjava.util.stream
.Большинство примеров, которые я рассмотрел, включают в себя использование этих API, которые, вероятно, очень распространены: преобразование между различными типами в API времени, например, для сравнений, которые, вероятно, часто выполняются между объектами, передаваемыми в функции или объекты, содержащиеся в коллекции. Мой вывод: если есть часть вашего API, которая должна быть гибкой, но вы можете покрыть, скажем, 80% случаев использования несколькими значениями по умолчанию, рассмотрите возможность использования статических методов в ваших интерфейсах. Учитывая, как редко эта функция используется в JDK, я буду очень консервативен, когда использую ее в своем собственном коде.
Ваши примеры не похожи на то, что я вижу в JDK. В этих конкретных случаях вы почти наверняка создадите интерфейс,
enum
который реализует желаемый интерфейс. Интерфейс описывает набор поведений и на самом деле не имеет бизнеса, поддерживающего коллекцию своих реализаций.источник
Как насчет совместимости со старыми JVM?
Нет. Это несовместимое назад изменение, которое добавляет пыль в выразительность языка. Два больших пальца вниз.
Я настоятельно рекомендую использовать классы, чтобы содержать детали реализации. Интерфейс на самом деле просто означает «этот объект поддерживает операции XYZ», и это не имеет никакого отношения к каким-либо статическим методам, которые вы можете себе представить в объявлении интерфейса. Эта функция похожа на кресло со встроенным мини-холодильником. Конечно, у него есть определенная ниша, но он не тянет достаточно веса, чтобы быть основным.
ОБНОВЛЕНИЕ: Пожалуйста, не более отрицательных голосов. Очевидно, что некоторые люди думают, что статические методы в интерфейсах - это колени пчелы, и я тем самым капитулирую. Я бы просто удалил этот ответ, но комментарии к нему - интересная дискуссия.
источник