Полиморфизм: зачем использовать "List list = new ArrayList "вместо"ArrayList list = new ArrayList"? [дубликат]


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

когда я должен использовать

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

ArrayList наследует от List, Так что если некоторые функции в ArrayList не в List, то я потеряю некоторые из особенностей ArrayList, да? И компилятор заметит ошибку при попытке доступа к этим методам?

8   126   2012-03-24 19:18:01

8 ответов:

основная причина, по которой вы это сделаете, - это отделить ваш код от конкретной реализации интерфейса. Когда вы пишете свой код так:

List list = new ArrayList();  

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

например, скажите, что вы писали довольно большую стороннюю библиотеку, и скажите, что вы решили реализовать ядро вашей библиотеки с LinkedList. Если ваша библиотека сильно зависит от доступа к элементам в этих списках, то в конечном итоге вы обнаружите, что вы приняли плохое дизайнерское решение; вы поймете, что вы должны были использовать ArrayList (что дает O (1) время доступа) вместо a LinkedList (что дает O (n) время доступа). Предполагая, что вы программировали на интерфейс, сделать такое изменение легко. Вы просто измените экземпляр List от,

List list = new LinkedList();

до

List list = new ArrayList();  

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

С другой стороны, если бы вы реализовали ядро своей библиотеки с помощью LinkedList list = new LinkedList(), сделать такое изменение было бы не так просто, так как нет никакой гарантии, что остальная часть вашего кода не использует методы, специфичные для LinkedList класса.

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

Это называется Программирование интерфейса. Это будет полезно в случае, если вы хотите переехать в другой реализации списка в будущем. Если вы хотите некоторые методы в ArrayList тогда вам нужно будет запрограммировать реализацию, которая ArrayList a = new ArrayList().

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

public ArrayList getList();

тогда вы решите изменить его на,

public LinkedList getList();

любой, кто делал ArrayList list = yourClass.getList() нужно будет изменить их код. С другой стороны, если вы

public List getList();

изменить ничего не меняет для пользователей вашего API.

Я думаю, что ответ @tsatiz в основном правильный (программирование на интерфейс, а не на реализацию). Однако,при программировании на интерфейс вы не потеряете никакой функциональности. Позвольте мне объяснить.

Если вы объявите переменную как List<type> list = new ArrayList<type> вы на самом деле не потерять любой функциональность ArrayList. Все, что вам нужно сделать, это бросить свой list до ArrayList. Вот пример:

List<String> list = new ArrayList<String>();
((ArrayList<String>) list).ensureCapacity(19);

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

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

Это позволяет вам написать что-то вроде:

void doSomething() {
    List<String>list = new ArrayList<String>();
    //do something
}

позже, вы можете изменить его на:

void doSomething() {
    List<String>list = new LinkedList<String>();
    //do something
}

без необходимости изменять остальную часть метода.

однако, если вы хотите использовать CopyOnWriteArrayList например, вам нужно будет объявить его как таковой, а не как список если вы хотите использовать ее дополнительные методы (addIfAbsent например):

void doSomething() {
    CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>();
    //do something, for example:
    list.addIfAbsent("abc");
}

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

кроме того, вы используете эту конструкцию, когда думаете, что можете захотеть изменить реализацию списка, который вы используете. Предположим, вы использовали конструкцию с ArrayList, и ваша проблема не была потокобезопасной. Теперь вы хотите сделать его потокобезопасным, и для части вашего решения вы меняете использование вектора, например. Что касается других применений этого списка, не имеет значения, является ли это Арарилистом или вектором, просто списком, никаких новых изменений не потребуется.

Я думаю, что суть вашего вопроса заключается в том, почему program to an interface, not to an implementation

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

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

, есть определенные ситуации, когда вы предпочитаете использовать конкретную реализацию. Например, при сериализации в GWT.