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

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

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

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

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

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

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

Ответ 1

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

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

Здесь хорошая статья по этому вопросу.

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

Ответ 2

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

Ответ 3

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

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

Для интереса я провел эксперимент, который сгенерировал десять миллиардов последовательных обращений к 1 миллиону ArrayList длины. На моем MacBook 2.4Ghz доступ к интерфейсу ArrayList через интерфейс List составлял в среднем 2.10 секунды, когда он объявлял его типа ArrayList, он занимал в среднем 1,67 секунды.

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

Ответ 4

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

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

Ответ 5

Почему последний должен использовать List вместо 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).*/

ИЛИ

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.*/

ИЛИ

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

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

ИЛИ

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

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

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

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

Ответ 6

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

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

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

Ответ 7

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

Однако...

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

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

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

Ответ 8

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

Ответ 9

Spring Framework прекрасно использует концепцию интерфейсов - http://www.springframework.org/

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

Исследование Spring иллюстрирует преимущества программирования на основе интерфейса на Java.

Ответ 10

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

Один интерфейс также имеет несколько реализаций. По сценарию система будет работать по другому сценарию (реализация интерфейса).

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