Почему интерфейс для класса Java должен быть предпочтительнее?

PMD сообщит о нарушении для:

ArrayList<Object> list = new ArrayList<Object>();

Нарушение было «Избегайте использования типов реализации, таких как« ArrayList », вместо этого используйте интерфейс».

Следующая строка исправит нарушение:

List<Object> list = new ArrayList<Object>();

Почему следует использовать последний с List вместо ArrayList?


person jnancheta    schedule 29.09.2008    source источник
comment
См. также stackoverflow.com/questions/383947/   -  person Raedwald    schedule 26.03.2014


Ответы (10)


Использование интерфейсов над конкретными типами является ключом к хорошей инкапсуляции и слабой связанности вашего кода.

Рекомендуется даже следовать этой практике при написании собственных API. Если вы это сделаете, позже вы обнаружите, что проще добавить модульные тесты в свой код (используя методы имитации) и изменить базовую реализацию, если это необходимо в будущем.

Вот хорошая статья на эту тему.

Надеюсь, поможет!

person kolrie    schedule 29.09.2008
comment
А как насчет использования Collection вместо List, чтобы сделать еще один шаг вперед в абстракции...? - person user1156544; 23.05.2018

Это предпочтительнее, потому что вы отделяете свой код от реализации списка. Использование интерфейса позволяет легко изменить реализацию, в данном случае ArrayList, на другую реализацию списка без изменения остального кода, если он использует только методы, определенные в List.

person AdamC    schedule 29.09.2008

В целом я согласен с тем, что отделение интерфейса от реализации — это хорошо, и это облегчит поддержку вашего кода.

Однако есть исключения, которые вы должны учитывать. Доступ к объектам через интерфейсы добавляет дополнительный уровень косвенности, который замедляет работу вашего кода.

Ради интереса я провел эксперимент, который сгенерировал десять миллиардов последовательных обращений к массиву ArrayList длиной в 1 миллион. На моем MacBook с частотой 2,4 ГГц доступ к ArrayList через интерфейс List занимал в среднем 2,10 секунды, при объявлении типа ArrayList это занимало в среднем 1,67 секунды.

Если вы работаете с большими списками, глубоко внутри внутреннего цикла или часто вызываемой функции, то это следует учитывать.

person Owen    schedule 30.09.2008
comment
@Owen: +5 Проницательный вопрос: Разница в производительности ... Очень неожиданно - person Ande Turner; 15.11.2008
comment
Однако этот ответ показывает, что накладные расходы могут быть очень небольшими: интерфейс"> stackoverflow.com/questions/890687/ - person Raedwald; 01.11.2011
comment
Вау! 0,5 секунды для десяти миллиардов обращений, т. е. доступ к 1 интерфейсу на полнаносекунды медленнее, чем доступ к классу! Это, конечно, причина никогда не использовать интерфейсы. - person Ingo; 13.10.2013

ArrayList и LinkedList — это две реализации списка, представляющего собой упорядоченный набор элементов. С точки зрения логики не имеет значения, используете ли вы ArrayList или LinkedList, поэтому вы не должны ограничивать этот тип.

Это контрастирует, скажем, с Collection и List, которые являются разными вещами (List подразумевает сортировку, а Collection — нет).

person SCdF    schedule 29.09.2008

Почему последний со списком должен использоваться вместо ArrayList?

Хорошая практика: Программируйте интерфейс, а не реализацию

Заменив ArrayList на List, вы можете изменить реализацию List в будущем, как показано ниже, в зависимости от вашего варианта использования в бизнесе.

List<Object> list = new  LinkedList<Object>(); 
/* Doubly-linked list implementation of the List and Deque interfaces. 
 Implements all optional list operations, and permits all elements (including null).*/

OR

List<Object> list = new  CopyOnWriteArrayList<Object>(); 
/* A thread-safe variant of ArrayList in which all mutative operations
 (add, set, and so on) are implemented by making a fresh copy of the underlying array.*/

OR

List<Object> list = new  Stack<Object>(); 

/* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/

OR

какая-то другая List конкретная реализация.

List интерфейс определяет контракт, а конкретная реализация List может быть изменена. Таким образом, интерфейс и реализация слабо связаны.

Связанный с SE вопрос:

Что значит программировать для интерфейса?

person Ravindra babu    schedule 27.12.2016
comment
А как насчет использования Collection вместо List, чтобы можно было использовать, например, List или Set - person user1156544; 23.05.2018

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

person Diastrophism    schedule 03.10.2008

Свойства ваших классов/интерфейсов должны быть доступны через интерфейсы, потому что это дает вашим классам контракт поведения для использования, независимо от реализации.

Тем не мение...

В объявлениях локальных переменных нет особого смысла делать это:

public void someMethod() {
List theList = new ArrayList();
//do stuff with the list
}

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

person MetroidFan2002    schedule 30.09.2008

Вообще для вашей строчки кода не имеет смысла заморачиваться с интерфейсами. Но если мы говорим об API, то на это есть веская причина. у меня маленький класс

class Counter {
    static int sizeOf(List<?> items) {
        return items.size();
    }
}

В этом случае требуется использование интерфейса. Потому что я хочу подсчитать размер каждой возможной реализации, включая мою собственную. class MyList extends AbstractList<String>....

person Rastislav Komara    schedule 29.09.2008
comment
Если вы кодируете такие реализации, как ArrayList, есть все шансы, что вы сможете использовать методы реализации, даже если вы можете сделать то же самое с методами интерфейса. Это свяжет ваш код с реализацией, что затруднит позднее переключение между реализациями. - person Champ; 01.05.2011

Интерфейс открыт для конечного пользователя. Один класс может реализовать несколько интерфейсов. Пользователь, который имеет доступ к определенному интерфейсу, имеет доступ к определенному поведению, которое определено в этом конкретном интерфейсе.

Один интерфейс также имеет несколько реализаций. На основе сценария система будет работать с разными сценариями (реализация интерфейса).

дайте мне знать, если вам нужно больше объяснений.

person sandeep garg    schedule 15.10.2019

Интерфейс часто имеет лучшее представление в представлении отладчика, чем конкретный класс.

person Kiruahxh    schedule 10.08.2020