11

Почему коллекции необходимо создавать таким образом:

List list = new Linkedlist();

Почему нежелательно сразу писать LinkedList?

Qwertiy
  • 123,725
Nojdon
  • 267

4 Answers4

20

Это важный прием написания хорошего ООП кода. Идея в том что так ваш код становится менее зависим от конкретных реализаций используемых модулей. В тот же самый интерфейс List можно записать LinkedList, ArrayList, CopyOnWriteArrayList и т.д.

При этом, объявив список подобным образом, мы можем быть уверены что если вдруг появится необходимость подменить реализацию с LinkedList на ArrayList, то нам придется изменить только строчку с вызовом конструктора. Например LinkedList, в отличии от ArrayList, помимо интерфейса List имплементирует ещё Queue(очередь) в котором есть метод push.

List list = new LinkedList();
LinkedList linkedList = new LinkedList();
ArrayList arrayList = new ArrayList();

list.add("ok");
linkedList.add("ok");
arrayList.add("ok");

list.push("error"); //ошибка при компиляции, у интерфейса List нет такого метода.
linkedList.push("Ok");
arrayList.push("error"); //ошибка при компиляции, ArrayList не имплементирует Queue

В примере выше, даже не смотря на то что в list у нас хранится экземпляр LinkedList, мы не можем вызвать специфичные для него методы. Интерфейс List вынуждает нас пользоваться только методами списка, а не очереди или чего-либо ещё.

Использование интерфейса вместо реализации не столь важно когда коллекция(или другой объект) создаётся и используется внутри одного метода, но важно если она каким-либо образом передаётся в другие модули.

Подробнее на эту тему читайте про SOLID.

  • Большое спасибо. Все стало понятно. – Nojdon Apr 16 '16 at 11:02
  • Это важно для типов параметров, но не для локальных переменных. В чём польза именно для локальных переменных? – Qwertiy Apr 17 '16 at 03:23
  • @Qwertiy т.е. код еще и теряет функционал(методы LL например) при написании List`a? А можно сначала написать List list = new LinckedList(); , а потом когда понадобятся мeтоды из LL переопределить как-нибудь? – Anton Sorokin Aug 24 '17 at 06:42
  • @антонсорокин, да, если у него есть особенные методы, не входящие в интерфейс. – Qwertiy Aug 24 '17 at 07:44
6

List — это интерфейс, а LinkedList - это класс, который имплементирует этот интерфейс. interface List содержит базовые методы add(), get(), remove() и так далее, если тебе достаточно этих методов можешь писать List<...> list = new LinkedList<..>(), если нужно использовать доп. методы которые есть в классе LinkedList тогда следует писать так LinkedList<...> linkedList = new LinkedList<...>();

  • Может наоборот? LinkedList это интерфейс List?и мне кажется, что тут явно есть причина почему нужно писать именно так, как я написал в примере. – Nojdon Apr 14 '16 at 18:28
  • @Nojdon, нет, не наоборот. Нельзя создать инстанс интерфейса. – Qwertiy Apr 14 '16 at 18:29
  • @Qwertiy сдается мне ТС имел в виду почему лучше писать List list = new Linkedlist(); а не Linkedlist list = new Linkedlist(); – Алексей Шиманский Apr 14 '16 at 18:40
  • @Qwertiy, а причём тут экземпляр интерфейса? Я говорю про то, что list это главный интерфейс, если точнее, то коллекция. И именно от него все другие коллекции имплеметируются – Nojdon Apr 14 '16 at 18:42
  • 3
    @Nojdon, List - это интерфейс, насколько я помню. LinkedList - класс, реализующий этот интерфейс. LinkedList не может быть интерфейсом, поскольку new Linkedlist() создаёт экземпляр, а экземпляр интерфейса создать нельзя. Поэтому утверждение "LinkedList это интерфейс List" неверно. – Qwertiy Apr 14 '16 at 18:44
  • @АлексейШиманский, я отвечал на его комментарий "Может наоборот? LinkedList это интерфейс List?", а не на вопрос. – Qwertiy Apr 14 '16 at 18:45
  • обновил ответ, теперь думаю стало яснее. – artemiygreg May 24 '17 at 11:51
0

Если ты захочешь из базы подтянуть какие-то сущности, которые в твоих репозиториях будут сохранятся как разные листы, тебе придется как минимум каждый раз чекать модель, чтобы посмотреть какой же там лист. А инициализируя через интерфейс ты на несколько секунд упрощаешь свою жизнь. Это один из примеров и таких можно навести еще много. К примеру, если ты изменил в модели лист с array на linked, но в сервисах или контроллерах подтягивал сущности именно в array, тогда тебе придется в ручную все изменять, но иницилизируя от интерфейса эта потребность отпадает.

calm27
  • 2,904
-1

Потому что это идеология джавы, объявлять переменные с типами интерфейса.

Но скоро это изменится:
https://habrahabr.ru/post/280188/
https://habrahabr.ru/post/280075/

val list = new Linkedlist();
Qwertiy
  • 123,725
  • Вот такой ответ меня и устраивает. Спасибо за конкретность и отдельно за ссылки. – Nojdon Apr 14 '16 at 18:51
  • А вот мне бы хотелось знать почему)) Ведь вопрос в этом. Почему они решили так, а не иначе. Не монетку же кидали. Есть этому какое-то правильное обдуманное объяснение на чем-то основанное – Алексей Шиманский Apr 14 '16 at 18:53
  • @АлексейШиманский - Потому что код надо писать в наиболее общем виде. Если дальнейшему коду достаточно типа List, то и переменную надо объявлять как List - так близко к базовому типу как это возможно. –  Apr 14 '16 at 19:02
  • Хорошо бы var, а ещё getter-ы n setter-ы как в c#. Про них ничего не слышно? – Sergey Apr 15 '16 at 11:20
  • @Sergey, я не джавист. – Qwertiy Apr 15 '16 at 11:56