В чем преимущество полиморфизма при использовании интерфейса Collection для создания объекта ArrayList? - PullRequest
8 голосов
/ 28 июля 2010

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

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

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();

Итак, моя путаница заключается в том, какая польза от объявления Коллекцией? Также я не знал, что вы можете иметь "Collection" (интерфейс, а не абстрактный класс) перед "myList".

Почему не стоит просто говорить:

ArrayList myList = new ArrayList();

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

Ответы [ 8 ]

10 голосов
/ 28 июля 2010

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

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

4 голосов
/ 28 июля 2010

Писать List<Something> myList = new ArrayList<Something>();, вероятно, чаще, чем использовать Collection.Обычно некоторые аспекты того, чтобы быть списком, важны.Неопределенность Collection в отношении принятия дублированных элементов, будь то набор или список (или что-то еще) под ними, может быть болезненной.

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

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

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

3 голосов
/ 28 июля 2010

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

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

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

Редактировать: сказав, что Generics также вводит некоторые Gotchas

List<Animal> может хранить ArrayList<Animal>, но не и ArrayList<Cat>.Вам нужно List<? extends Animal>, чтобы хранить ArrayList<Cat>.

1 голос
/ 30 ноября 2012

Ну, у arraylist есть динамический размер. Коллекция не проверяется во время компиляции, она должна быть напечатана. Коллекция содержит только объекты по ссылке. Вы можете думать о коллекции как о «сумке». И манипуляции могут быть выполнены над всем объектом. Я также уверен, что время поиска для коллекции короткое по сравнению с ArrayList, но не является положительным. ArrayLists имеют больше функций и методов, которые можно вызывать.

1 голос
/ 29 июля 2010

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

Рассмотрим:

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

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

public void removeNames(List words) ...  

Я мог бы заменить тип слова словами List. Это не не имеет никакого значения для читаемости или поведения моей программы. Я не мог определить слова как Object. Это слишком общее.

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

ArrayList words = new ArrayList();

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

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

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

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

1 голос
/ 28 июля 2010

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

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

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

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

0 голосов
/ 28 июля 2010

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

0 голосов
/ 28 июля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...