Я видел такой код много раз:
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
в будущем.