Поскольку в вашем примере используется приватное поле , не имеет особого значения скрытие типа реализации.Вы (или тот, кто поддерживает этот класс) всегда можете просто взглянуть на инициализатор поля и посмотреть, что это такое.
В зависимости от того, как он используется, возможно, стоит объявить более конкретный интерфейс для поля,Объявление значения List
означает, что дубликаты разрешены и что порядок важен.Объявление значения Set
означает, что дубликаты не допускаются и что порядок не имеет значения.Вы могли бы даже объявить поле, чтобы иметь определенный класс реализации, если есть что-то существенное в нем.Например, объявление его как LinkedHashSet
означает, что дубликаты недопустимы, но этот порядок имеет значение .
Выбор того, использовать ли интерфейс и какой интерфейс использовать,становится намного более значимым, если тип появляется в общедоступном API класса и о том, каковы ограничения совместимости для этого класса.Например, предположим, что существует метод
public ??? getRegisteredListeners() {
return ...
}
Теперь выбор типа возвращаемого значения влияет на другие классы.Если вы можете изменить всех абонентов, возможно, это не имеет большого значения, вам просто нужно отредактировать другие файлы.Но предположим, что вызывающая сторона - это приложение, которое вы не можете контролировать.Теперь выбор интерфейса имеет решающее значение, так как вы не можете изменить его, не взломав приложения.Правило здесь обычно состоит в том, чтобы выбрать наиболее абстрактный интерфейс, который поддерживает операции, которые, как вы ожидаете, будут выполнять вызывающие абоненты.
Большинство API Java SE возвращают Collection
.Это обеспечивает достаточную степень абстрагирования от базовой реализации, но также предоставляет вызывающей стороне разумный набор операций.Вызывающая сторона может выполнить итерацию, получить размер, выполнить проверку содержимого или скопировать все элементы в другую коллекцию.
Некоторые базы кода используют Iterable
в качестве наиболее абстрактного интерфейса для возврата.Все, что он делает, это позволяет вызывающей стороне выполнять итерации.Иногда это все, что необходимо, но это может быть несколько ограничивающим по сравнению с Collection
.
Другая альтернатива - вернуть Stream
.Это полезно, если вы думаете, что вызывающий может захотеть использовать операции потока (такие как фильтр, отображение, поиск и т. Д.) Вместо итерации или использования операций сбора.
Обратите внимание, что если вы решите вернуть Collection
или Iterable
, вам необходимо убедиться, что вы возвращаете неизменяемое представление или делаете защитную копию.В противном случае вызывающие могут изменить внутренние данные вашего класса, что, вероятно, приведет к ошибкам.(Да, даже Iterable
может разрешить изменение! Подумайте о получении Iterator
и вызове метода remove()
.) Если вы возвращаете Stream
, вам не нужно об этом беспокоиться, так как вы можете '* Используйте 1033 * для изменения базового источника.
Обратите внимание, что я превратил ваш вопрос об объявлении поля в вопрос об объявлении возвращаемых методов.Существует идея «программы для интерфейса», которая довольно распространена в Java.По моему мнению, это не имеет большого значения для локальных переменных (именно поэтому обычно хорошо использовать var
), и это не имеет большого значения для частных полей, так как те (почти) по определению влияют только на класс, в котором они 'объявлен.Однако принцип «программа к интерфейсу» очень важен для сигнатур API, поэтому вам нужно подумать о типах интерфейса.Частных полей, не так уж много.
(Последнее замечание: есть случай, когда вам нужно заботиться о типах частных полей, и именно тогда вы используете отражающую среду, которая напрямую управляет частными полями.В этом случае вам нужно думать об этих полях как об открытых - так же, как о типах возвращаемых методов - даже если они не объявлены public
.)