Что преимущество полиморфизма использует интерфейс Collection для создания объекта ArrayList?

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

Предположение, что класс Животное является абстрактным классом.

public class AnimalReference
{
  public static void main(String args[])
  Animal ref                 // set up var for an Animal
  Cow aCow = new Cow("Bossy"); // makes specific objects
  Dog aDog = new Dog("Rover");

  // now reference each as an Animal
  ref = aCow; ref.speak();
  ref = aDog; ref.speak();
}

Я раньше создавал экземпляр ArrayList как:

ArrayList myList = new ArrayList();

Но обычно я полагал, что люди пишут:

Collection myList = new ArrayList();

Таким образом, мой беспорядок - то, что преимущество объявления как Набор? Также я не знал, что у Вас может быть "Набор" (который является интерфейсом не абстрактный класс) перед "myList".

Почему это не хорошая практика, чтобы просто сказать:

ArrayList myList = new ArrayList();

Я считал интерфейс Collection и документы ArrayList Java, а также учебные руководства онлайн, но все еще действительно очищаюсь.. Кто-либо мог дать мне некоторое объяснение?

8
задан masato-san 28 July 2010 в 18:23
поделиться

7 ответов

Если вы объявляете myList как ArrayList , вы фиксируете его конкретный тип. Каждый, кто его использует, будет зависеть от этого конкретного типа, и легко (даже непреднамеренно) вызвать методы, специфичные для ArrayList . Если когда-нибудь позже вы решите изменить его, например, на LinkedList или CopyOnWriteArrayList , вам необходимо перекомпилировать - и, возможно, даже изменить - код клиента. Программирование интерфейсов устраняет этот риск.

Обратите внимание, что между Collection и ArrayList существует другой уровень абстракции: интерфейс List . Обычно схема использования списка сильно отличается от схемы, набора или очереди. Таким образом, тип сбора, который вам нужен для работы, обычно определяется на раннем этапе и не будет меняться. Объявление вашей переменной как List проясняет это решение и предоставляет своим клиентам полезную информацию о контракте, которому подчиняется эта коллекция. Коллекция OTOH обычно не очень полезен для чего-то большего, чем итерация по его элементам.

11
ответ дан 5 December 2019 в 08:22
поделиться

Если вы объявляете ArrayList , я бы никогда не использовал ArrayList в качестве типа слева. Вместо этого запрограммируйте интерфейс, будь то List или Collection .

Обратите внимание, что если вы объявляете метод как принимающий Collection , ему можно передать List или Set .

В качестве примечания, рассмотрите возможность использования Generics .

Edit: Сказав это, Generics также вводит некоторые проблемы.

List может хранить ArrayList , но не an ArrayList . Вам понадобится Список для хранения ArrayList .

3
ответ дан 5 December 2019 в 08:22
поделиться

Вероятно, чаще пишут Список myList = new ArrayList (); , чем использовать Collection . Обычно некоторые аспекты того, что это список, имеют значение. Расплывчатость Коллекции в отношении принятия повторяющихся элементов, будь то набор или список (или что-то еще), может быть проблемой.

Помимо этого, основная цель - абстракция или независимость от реализации. Меня действительно волнует, является ли мой список ArrayList или вектором ? Наверное, не в большинстве случаев. Мой код будет более гибким, если он использует самый общий интерфейс, который выражает то, что мне нужно от объекта.

Простой пример: предположим, что вы пишете программу, использующую все ArrayList , а позже она должна поддерживать нескольких пользователей, поэтому для обеспечения безопасности потоков вы хотите изменить весь свой ArrayList ] s на Vecto rs. Если вы проходили ссылки на Type ArrayList , вам нужно везде менять каждое использование. Если вы проходили ссылки на Список типов , вам нужно только изменить места, где вы их создаете.

Кроме того, иногда реализующий класс не может быть тем, что вы можете или хотите импортировать и использовать. Например, при использовании поставщика сохраняемости, такого как hibernate, фактический класс, реализующий интерфейс Set , может быть узкоспециализированной пользовательской реализацией, уникальной для платформы, или это может быть просто старый HashSet , в зависимости от того, как объект был создан.Вам наплевать на разницу, для вас это просто Set .

3
ответ дан 5 December 2019 в 08:22
поделиться

Тип, который вы используете в объявление локальной переменной (как в вашем ArrayList пример) обычно не так важен. Все, что вам нужно убедиться, это что тип myList (слово слева от имени myList) имеет чтобы быть более конкретным, чем тип любого параметра метода, который принимает мой список.

Подумайте:

ArrayList words = new ArrayList();
sort(words);
removeNames(words);

public void sort(Collection c)  ... blah blah blah

public void removeNames(List words) ...  

Я мог бы заменить тип «слова» просто списком. Это не иметь какое-либо значение для удобочитаемости или поведения моей программы. Однако я не мог определить «слова» как объект. Это слишком общее.

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

ArrayList words = new ArrayList();

// this line will cause a compilation error.
sort(words);

public void sort(LinkedList c)  ... blah blah blah

Определение сортировки теперь очень ограничительно. В первом примере метод сортировки допускает любой объект в качестве параметра, если он реализует Collection. Во втором примере сортировка позволяет только LinkedList, он не примет ничего другого (ArrayLists, HashSets, TreeSets и многие другие). Сценарии, в которых метод сортировки может возможность использования сейчас весьма ограничена. Это могло быть по уважительной причине; в реализация сортировки может полагаться на функцию LinkedList структура данных. Только плохо определять сортировку таким образом, если люди, использующие этому коду нужен алгоритм сортировки, который работает не только для LinkedLists.

Один из основных навыков написания java-библиотек - выбор типов параметров метода. Насколько общим вы хотите быть?

1
ответ дан 5 December 2019 в 08:22
поделиться

Объявляя и используя myList как Collection, вы скрываете выбор реализации, который вы делаете (в данном случае, что он представлен как ArrayList). В общем, это означает, что все, что зависит от вашего кода, будет зависеть только от поведения myList как коллекции, а не как ArrayList в частности. Таким образом, если вы решите позже представить его как что-то другое (набор? связанный список?) по какой-либо причине, вы не нарушите ничего другого.

0
ответ дан 5 December 2019 в 08:22
поделиться

Коллекция является супертипом ArrayList . Если вам нужны только функции, предоставляемые коллекцией , это хорошая практика, потому что вы явно указываете, какие функции вам нужны в объявлении переменной . То, что вы выбрали ArrayList в инициализации , не имеет значения (хотя это хороший выбор по умолчанию); объявление, что это Коллекция , сообщает вам и любому будущему программисту, какой именно контракт вас волнует.

0
ответ дан 5 December 2019 в 08:22
поделиться

Прежде всего, есть существенная разница между наследованием и интерфейсами. Небольшой экскурс в историю: В старом добром С++ вы могли наследоваться от нескольких классов. Это имело негативные последствия, если класс "Transformer" наследуется от классов "Vehicle" и "Human", оба из которых реализуют метод "MoveForward". Какую функцию должен использовать экземпляр при вызове этого метода в классе "Трансформер"? Реализацию "Человека" или "Транспортного средства"? Для решения этой проблемы в java, c#, ... введены интерфейсы. Интерфейсы - это контракт между вашим классом и чем-то другим. Вы берете на себя обязательства по функциональности, но контракт НЕ реализует никакой логики для вашего класса (чтобы предотвратить проблему Transformer.MoveForward").

Полиморфизм в целом означает, что что-то может появляться разными способами. Трансформер" может быть "транспортным средством" и "человеком". В зависимости от языка (я использую C#) вы можете реализовать различное поведение для "MoveForward", в зависимости от контракта, который вы хотите выполнить.

Использование интерфейсов вместо конкретной реализации имеет несколько преимуществ. Во-первых, вы можете менять реализацию без изменения кода (Dependency Injection для поиска в google ;)). Во-вторых, вы можете легче тестировать свой код с помощью фреймворков тестирования и mocking-фреймворков. В-третьих, хорошей практикой является использование наиболее обобщенного интерфейса обмена данными (перечислитель вместо списка, если вы хотите работать только со значениями).

надеюсь, это немного поможет понять преимущества интерфейсов.

1
ответ дан 5 December 2019 в 08:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: