2008-09-29 4 views
66

PMD сообщит о нарушении правил для:Зачем нужен интерфейс для класса Java?

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

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

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

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

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

+0

Смотрите также HTTP: // StackOverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface – Raedwald 2014-03-25 23:48:04

ответ

73

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

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

Вот good article по теме.

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

27

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

5

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

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

0

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

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

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

+0

Если вы кодируете такие реализации, как ArrayList, есть все возможности, что вы можете использовать методы реализации, даже если вы можете сделать то же самое с методами интерфейса. Это привяжет ваш код к реализации, что затрудняет переход между реализациями позже. – Champ 2011-05-01 08:37:59

1

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

Однако ...

В деклараций локальных переменных, это не имеет никакого смысла, чтобы сделать это:

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

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

10

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

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

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

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

+0

@Owen: +5 Проницательный повтор: разница в производительности ... Очень неожиданно – 2008-11-15 06:39:52

1

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

0

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

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

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

1

Зачем использовать последний со списком вместо 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 может быть изменена. Таким образом, интерфейс и реализация слабо связаны.

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

What does it mean to "program to an interface"?

 Смежные вопросы

  • Нет связанных вопросов^_^