Я видел такой код много раз:
List<String> list = new ArrayList<String>();
Почему люди берут родительский элемент ArrayList (и других классов) вместо типа сгенерированного объекта?
Это снижает производительность? Или зачем кому-то это делать?
Я видел такой код много раз:
List<String> list = new ArrayList<String>();
Почему люди берут родительский элемент ArrayList (и других классов) вместо типа сгенерированного объекта?
Это снижает производительность? Или зачем кому-то это делать?
Когда кто-то пишет такой код, он/она пытается следовать основному принципу дизайна OO, который говорит -
Программа для интерфейса, а не для конкретной реализации
Я объяснил этот принцип в одном из моих сообщений в блоге. Посмотрите раздел Class Inheritance VS Interface Inheritance.
Чтобы суммировать сообщение, когда вы используете ссылку родительского типа для ссылки на экземпляр подтипа, вы получаете большую гибкость. Например, если вам когда-либо понадобится изменить реализацию подтипа в будущем, вы сможете сделать это легко, не изменяя большую часть своего кода.
Рассмотрим следующий метод -
public void DoSomeStuff(Super s) {
s.someMethod();
}
и вызов этого метода -
DoSomeStuff(new Sub());
теперь, если вам когда-либо понадобится изменить логику внутри someMethod, вы можете легко сделать это, объявив новый подтип Super, скажем NewSubType, и изменив логику внутри этой реализации. Таким образом, вам никогда не придется касаться другого существующего кода, который использует этот метод. Вы все равно сможете использовать свой метод DoSomeStuff следующим образом:
DoSomeStuff(new NewSubType());
Если бы вы объявили параметр DoSomeStuff равным Sub, вам также пришлось бы изменить его реализацию -
DoSomeStuff(NewSubType s) {
s.someMethod();
}
и он может также цепью/пузырьком в нескольких других местах.
Что касается примера вашей коллекции, это позволяет вам изменить реализацию списка, на которую указывает переменная, без особых хлопот. Вы можете легко использовать LinkedList вместо ArrayList.
Это означает, что вы можете поменять тип list в любой точке на все, что реализует интерфейс list, в отличие от создания жесткой модели, которая может использовать только ArrayList. Например:
private List<String> list;
public SomeConstructor()
{
// At this point, you can make it any type of object you want.
list = new ArrayList<String>();
list = new LinkedList<String>();
list = new AttributeList<String>();
}
Это будет abstract ваш код, который использует объект list, вдалеке от деталей, таких как точный тип объекта list. Все, что ему нужно знать, это то, что у него есть метод add и т.д. Это называется Loose Coupling.
Когда вы пишете:
List<String> list = new ArrayList<String>();
Тогда вы уверены, что будете использовать только функциональные возможности интерфейса List.
(ArrayList реализует List, поэтому List больше flexibl).
Используя это, вы можете изменить ArrayList на другие типы в будущем (например, LinkedList..).
Чтобы разобраться:
Для большей гибкости вы инициируете интерфейс List:
Итак, если вам не нужно все ArrayList использовать только List.
Вы можете написать что-то вроде: List<String> = Arrays.asList("aa", "bb","cc").
Конечно, меньшая функциональность может помочь в производительности. Как вы знаете, если вы хотите использовать многопоточное приложение, используйте Vector, но он снизит вашу производительность.

Взял из здесь
Поскольку метод не должен знать, какую версию-реализацию вы используете.
Метод просто должен знать, что есть список.
Метод все еще можно использовать.
Всегда программируйте интерфейс, а не конкретную реализацию. (В этом случае List)
В общем случае предпочтительнее работать с классом Interface (List в этом случае), так что любая реализация списка впоследствии может быть заменена минимальной проблемой при изменении требований.
Хотя ArrayList возможно поддерживает некоторые методы, которые не находятся в интерфейсе List, это выражение позволяет понять, что эти дополнительные методы в этом случае не актуальны.
List<String> list = new ArrayList<String>();
В рамках коллекции List есть интерфейс, а ArrayList - реализация. Основная причина, по которой вы это сделаете, состоит в том, чтобы отделить ваш код от определенного implementation интерфейса, и это будет полезно в случае, если вы захотите перейти к другой реализации List в будущем.