Polimorfismo: Por que usar “List list = new ArrayList” ao invés de “ArrayList list = new ArrayList”?

Duplicar Possível:
Por que a interface para uma class Java deve ser preferida?

Quando devo usar

List list = new ArrayList(); 

ArrayList herda da List , por isso, se alguns resources em ArrayList não estão na List , então eu vou ter perdido alguns dos resources do ArrayList , certo? E o compilador irá notar um erro ao tentar acessar esses methods?

A principal razão pela qual você faria isso seria dissociar seu código de uma implementação específica da interface. Quando você escreve seu código assim:

 List list = new ArrayList(); 

o resto do seu código só sabe que os dados são do tipo List , o que é preferível porque permite alternar entre diferentes implementações da interface List com facilidade.

Por exemplo, digamos que você estava escrevendo uma biblioteca de terceiros bastante grande e diga que decidiu implementar o núcleo da sua biblioteca com um LinkedList . Se a sua biblioteca depende muito do access a elementos nessas listas, você acabará descobrindo que tomou uma decisão ruim de design; você perceberá que deveria ter usado um ArrayList (que fornece o tempo de access O (1)) em vez de um LinkedList (que fornece o tempo de access O (n)). Supondo que você esteja programando para uma interface, fazer essa mudança é fácil. Você simplesmente mudaria a instância de List de,

 List list = new LinkedList(); 

para

 List list = new ArrayList(); 

e você sabe que isso funcionará porque você escreveu seu código para seguir o contrato fornecido pela interface List .

Por outro lado, se você tivesse implementado o núcleo da sua biblioteca usando LinkedList list = new LinkedList() , fazer essa mudança não seria tão fácil, pois não há garantia de que o resto do seu código não faça uso de methods específicos para a class LinkedList .

Em suma, a escolha é simplesmente uma questão de design … mas este tipo de design é muito importante (especialmente quando se trabalha em grandes projetos), pois permitirá que você faça alterações específicas da implementação mais tarde sem quebrar o código existente.

Isso é chamado de programação para interface. Isso será útil caso você queira mudar para outra implementação da Lista no futuro. Se você quer alguns methods em ArrayList então você precisaria programar para a implementação que é ArrayList a = new ArrayList() .

Isso também é útil ao expor uma interface pública. Se você tem um método como esse,

 public ArrayList getList(); 

Então você decide mudar para,

 public LinkedList getList(); 

Qualquer pessoa que estivesse fazendo ArrayList list = yourClass.getList() precisará alterar seu código. Por outro lado, se você fizer isso,

 public List getList(); 

Alterar a implementação não muda nada para os usuários da sua API.

Eu acho que a resposta do @ tsatiz está mais correta (programar para uma interface ao invés de uma implementação). No entanto, ao programar para a interface, você não perderá nenhuma funcionalidade . Deixe-me explicar.

Se você declarar sua variável como List list = new ArrayList , não perderá realmente nenhuma funcionalidade do ArrayList. Tudo o que você precisa fazer é converter sua list em uma ArrayList . Aqui está um exemplo:

 List list = new ArrayList(); ((ArrayList) list).ensureCapacity(19); 

No fim das contas, acho que tsatiz está correto, já que uma vez que você lança em uma ArrayList, você não está mais codificando para uma interface. No entanto, ainda é uma boa prática codificar inicialmente para uma interface e, se mais tarde for necessário, codificar para uma implementação, se necessário.

Espero que ajude!

Isso permite que você escreva algo como:

 void doSomething() { Listlist = new ArrayList(); //do something } 

Mais tarde, você pode querer alterá-lo para:

 void doSomething() { Listlist = new LinkedList(); //do something } 

sem ter que mudar o resto do método.

No entanto, se você quiser usar um CopyOnWriteArrayList por exemplo, será necessário declará-lo como tal e não como uma Lista, se quiser usar seus methods extras (addIfAbsent, por exemplo):

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

Eu uso essa construção sempre que não quero adicionar complexidade ao problema. É apenas uma lista, não há necessidade de dizer que tipo de lista é, pois não importa o problema. Costumo usar a Coleção para a maioria das minhas soluções, pois, no final, na maioria das vezes, para o restante do software, o que realmente importa é o conteúdo que contém e não quero adicionar novos objects à Coleção. .

Além disso, você usa essa construção quando acha que pode querer alterar a implementação da lista que está usando. Digamos que você estivesse usando a construção com um ArrayList e seu problema não era seguro para threads. Agora, você quer torná-lo seguro, e para parte da sua solução, você pode mudar para usar um Vector, por exemplo. Quanto aos outros usos dessa lista, não importa se é uma AraryList ou um Vector, apenas uma List, nenhuma nova modificação será necessária.

Eu acho que o núcleo da sua pergunta é por que program to an interface, not to an implementation

Simplesmente porque uma interface fornece mais abstração e torna o código mais flexível e resiliente a mudanças, porque você pode usar diferentes implementações da mesma interface (nesse caso, você pode querer alterar sua implementação de Lista para um linkedList em vez de um ArrayList) sem alterar seu cliente.

Em geral, você deseja programar em uma interface. Isso permite que você troque a implementação a qualquer momento. Isso é muito útil, especialmente quando você recebe uma implementação que você não conhece.

No entanto, existem certas situações em que você prefere usar a implementação concreta. Por exemplo, quando serializar no GWT.