List X ArrayList (pq implementar uma interface?)

Olás

Já andei pesquisando e sei como trabalhar com os Arrays, mas o que eu não entendo (e não encontro explicação) é por que normalmente há uma referência da interface List para o ArrayList.

tipo:

List<String> words = new ArrayList<String>();

Se List é uma interface e ArrayList a implementa, não deveria ser a mesma coisa se fizéssemos isso:

ArrayList<String> words = new ArrayList<String>();

Já que “ArrayList implements List”, já não estaríamos herdando essa interface instanciando ArrayList?

Parece bizarro é instanciar uma interface… (ou preciso estudar mais rs) mas não vejo essas referências a interfaces nos códigos por aí.

vlw

Por um motivo simples: ArrayList não é a única coisa que implementa List. Se você quiser trocar a implementação, é muito mais simples fazê-lo se você sempre referenciar o tipo da interface.
Olhe estes dois exemplos:[code]public class CoisaQualquer {
public ArrayList numeros() {
ArrayList nums = new ArrayList();
nums.add(1);
nums.add(2);
nums.add(3);
return nums;
}

public void mostraNumeros() {
    ArrayList<Integer> nums = numeros();
    for (Integer i : nums) {
        System.out.println(i);
    }
}

}[/code][code]public class CoisaQualquer {
public List numeros() {
List nums = new ArrayList();
nums.add(1);
nums.add(2);
nums.add(3);
return nums;
}

public void mostraNumeros() {
    List<Integer> nums = numeros();
    for (Integer i : nums) {
        System.out.println(i);
    }
}

}[/code]Vamos supor, que por qualquer motivo, você decida usar LinkedList, ou uma lista baseada em arrays ao invés de ArrayList:public List<Integer> numeros() { List<Integer> nums = new LinkedList<Integer>(); nums.add(1); nums.add(2); nums.add(3); return nums; }public List<Integer> numeros() { return Arrays.asList(new Integer[] {1, 2, 3}); }O que acontece? Se o tipo de retorno do método for ArrayList ao invés de List, você vai ter que mudar o tipo de retorno do método. Ao fazer isso, você pode acabar quebrando compatibilidade com outros lugares que usam o tipo de retorno ArrayList ao invés de List (como, por exemplo, o método mostraNumeros e provavelmente outros 500 lugares na sua aplicação), isso faz com que voce acabe tendo que ter todo o trabalho de mudar um a um esses lugares, ou então fazer uma gambiarra de criar um ArrayList no meio do caminho e copiar os elementos só porque você está usando o tipo errado e o compilador percebeu isto.
É esse que é o famoso (e pouco entendido) conceito “code to an interface”. Isso significa, basicamente, “use o tipo mais genérico possível que você puder usar”.

1 curtida

Pense na coisa + ou - como uma peneira…

se vc afirma por exemplo em um método seu, que vc ker um ArrayList, vc esta reduzindo as possibilidades, so vai aceitar um ArrayList ou algo que venha dele, isso vai depender da sua aplicação, se ela depende diretamente que vc tenha uma ArrayList e não uma List, ou seja, se existem métodos que só existe em ArrayList e que vc precisa usar, então vc deve referenciar pela ArrayList e não pela List…

digamos que vc tenha um Objeto chamado de Pessoa, e que este objeto tenha uma lista de Telefones então vc teria nele algo assim…

[code]public class Pessoa {
//outros fields…
private ArrayList telefones = new ArrayList(0);

public void setTelefone(ArrayList telefones) {
this.telefones = telefones;
}
public ArrayList getTelefones() {
return telefones;
}
//outro métodos…
}[/code]

blz tua classe ta funcionando perfeitamente… porem digamos agora que vc começou a usar Hibernate, para ler os dados de um banco de dados, e que vc pessa pra ele ler a lista de pessoas, o Hibernate retorna um objeto List, porem esse objeto List do hibernate é um HibernateList e não vem de ArrayList… portanto ao fazer essa consulta, vc não consiguirar usar algo como pessoa.setTelefones(HibernateUtils.list(Pessoa.class)), para tal vc teria q criar uma ArrayList e transfir os dados do HibernateList para sua lista…

agora se tua classe estiver pronta para receber List no lugar de ArrayList … qualquer que seja a implementação da interface List… vc poderar aceitar…

[code]public class Pessoa {
//outros fields…
private List telefones = new ArrayList(0);

public void setTelefone(List telefones) {
this.telefones = telefones;
}
public List getTelefones() {
return telefones;
}
//outro métodos…
}[/code]

veja q nesse exemplo acima, vc continua usando ArrayList no seu campo telefones… veja que vc ainda poder fazer pessoa.setTelefones(arrayList) porem vc aumentou as possibilidades aceitando tb pessoa.setTelefones(qualquerList) …

isso é uma questão de necessidade… c vc so precisa dos métodos inerentes a List, não há motivos para restringir a ArrayList

[quote=pgnt]Olás

Já andei pesquisando e sei como trabalhar com os Arrays, mas o que eu não entendo (e não encontro explicação) é por que normalmente há uma referência da interface List para o ArrayList.

tipo:

List<String> words = new ArrayList<String>();

Se List é uma interface e ArrayList a implementa, não deveria ser a mesma coisa se fizéssemos isso:

[/quote]

Java é OO e tem uma propriedades chamada Polimorfismo. Em especial uma chamada Variável Polimórfica.

É boa prática declarar a sua variável de forma polimórfica. Ou seja, delcará-la com o tipo mais abstrato que ainda faz o serviço.
No caso, List é o tipo mais abstrato que faz o serviço ( mas poderia ser Collection, por exemplo)

Esta prática é conhecida como “programar para interfaces” mas nada é mais além de usar OO e polimorfismo para ter um codigo mais simples e de mais fácil manutenção.

Diferentemente do C++ e do C#, não há perda de desempenho em referenciar algo através de sua interface em vez da classe.
O JIT (Just-In-Time Compiler) do Java faz algumas otimizações e uma chamada “virtual” (usando a terminologia do C++ e do C#) é transformada em uma chamada não-virtual se isso for possível no seu programa (como é o caso do seu exemplo, onde uma variável já recebe um valor de uma determinada classe e o tipo do objeto não muda em tempo de execução).

[quote=Lavieri]
isso é uma questão de necessidade… c vc so precisa dos métodos inerentes a List, não há motivos para restringir a ArrayList[/quote]

E mesmo que se venha a precisar de métodos inerentes unicamente à ArrayList ainda se pode fazer um castdown.

Ola pessoal… venho estudando java a algum tempo e com as respostas contidas nessa discução, eu to conseguindo entender um pouco melhor a expressão “code to an interface”…

Mas através dos meus estudos e pesquisas surgiram umas outras duvidas…

Gostaria da opinião dos mais experientes e me responder as seguintes questões:

:arrow: Podemos “modelar” um sistema apenas utilizando interfaces? E depois só criarmos um implementação para cada uma deslas? Éssa é a ideia não é? :roll:
:arrow: É certo afirmar então, que uma boa pratica de POO é que um objeto, não digo sempre, mas " quase sempre" deveria implementar uma interface?(pq deve ter casos especificos que nessecite o contrario né?) ou estou superestimando o uso de delas (interfaces)? :lol:

Valeu pela atenção pessoal.

Felipe

Por favor pessoal… esclareçam minhas duvidas :cry:

[quote=Malkav.Felipe] :arrow: Podemos “modelar” um sistema apenas utilizando interfaces? E depois só criarmos um implementação para cada uma deslas? Éssa é a ideia não é? :roll:

:arrow: É certo afirmar então, que uma boa pratica de POO é que um objeto, não digo sempre, mas " quase sempre" deveria implementar uma interface?(pq deve ter casos especificos que nessecite o contrario né?) ou estou superestimando o uso de delas (interfaces)? :lol:[/quote]
Não. Não há sentido em usar interfaces pra tudo, pode ser que alguns de seus objetos sejam inerentemente concretos.

Sem falar que modelamos para conceitos, não para linguagens. Não importa que Telefone seja interface ou classe, o que importa é que queremos um Telefone.

Enfim, não procure polimorfismo onde não tem, e seja simples e pragmático, se ficar fazendo só interfaces, vai esquecer que tem um sistema concreto pra fazer.

Uma coisa que pode te ajudar a entender quando é necessario uma interface…

pense da seguinte forma, interface representa um comportamento… vc pode ter varios objetos destintos, onde cada um destes objetos tem uma Hieraquia propia, porem pode exister um comportamento em comum entre eles, se esse comportamente te interessar essa é a hora de usar interfaces…

Por exemplo, "Fazer Som" já imaginou quantos objetos distintos podem existir no mundo que são capazes de emitir som ?? é impossivel fazer isso por herança, mais digamos que vc precise por alguma rotina, emitir o som de diversos objetos ?? como fazer ?? como ter uma sacola com uns 40 … 500 … 1000 tipos diferentes de objetos e conseguir tocar o som de todos ?? quando vc vai num aparelho de DVD o que vc procura pra tocar som ?? uma imagem + ou - assim |> akele botãozinho de play … pois é aquilo é uma interface, interface é uma forma de comunicação comum a varios objetos…

Em programação isso pode ser feito, disponibilizando um contrato por exemplo…

public interface EmitidorDeSom { public void playSom(); }

pronto agora vc tem um contrato, uma forma de comunicar a alguem como vc interpreta que aquile objeto Emite som, ali esta o seu contrato… agora vc pode programar, de forma generica, pra tocar o som de qualquer objeto

public void emiteSomDeTodosObjetos(List objetos) { for(Object objeto: objetos) { if (objeto instanceof EmitidorDeSom) EmitidorDeSom emitiSom = (EmitidorDeSom)objeto; emiteSom.playSom(); } } }

o que esse método faz ?? ele pega uma lista de objetos, verifica um por um, se ele assina o contrato de EmtidorDeSom, caso positivo, ele faz um cast, do objeto, para um emitidor de som, ele simplismente esquece tudo que o objeto pode representar, e olha apenas para a interface dele de emitidor de som… nessa interface ele ativa o método
playSom() … e mesmo sem saber que objeto se trata, ele consegue emitir o seu som…

E agora sabendo disso… como criar um aparelho proprio ? que emite som ?? … digamos que vc seja louco e projetou um bone que emite som… vc não precisa descender o seu bone direto de um MP3 player… basta vc em seu bone que emite som, assinar o contrato de emitir som…

[code]public class BoneSomzera implements EmitidorDeSom { //implements EmitidorDeSom siginifica que vc assinou o contrato
private Color cor
private int tamanho;
private boolean aba;
private boolean couro;

//alguns métodos do seu bone

//dentro dele, obrigatoriamente, vc precisa implementar o método do contrato que vc assinou...
public void playSom() {
     System.out.println("BoneSomzera começa a emitir sons malucos...");
     //... pronto aqui dentro vc emite o som do seu bone....
}

}[/code]

Pronto, agora qualquer objeto que conheça o contrato EmitidorDeSom, pode tocar o som do seu Bone, mesmo sem conhecer o funcionamento dele, e mesmo sem obriga-lo a descender de um Tocador de som genérico… é pra isso que existem as interfaces, para Definir contratos uteis ao seu modelo (ou comportamentos uteis ao seu modelo)…

Um exemplo, que eu uso muito nos meus modelos é uma interface chamda Sizable eu tenho varios objetos no meu modelo que tem um referencial de quantidade, como estoque (que tem quantidade), entre varios outros objetos uteis… para ter uma forma comum de verificar o tamanho de varios objetos eu criei essa interface

public interface Sizable { public boolean isEmpty(); public int size(); }

toda calsse no meu modelo, que tem quantidade, eu assino o contrato de Sizable, e implemento os 2 métodos… assim posso ter métodos genericos, que testam consistencia dos meus objetos, por exemplo, eu para alguns objetos, preciso verificar se ele esta vazio e se estiver, lançar uma exceção de erro, por não aceitar objetos vazio eu tenho um método na minha classe Consistences.notEmpty(Sizable obj); onde ele verifica se o tamanho é vazio e se for, lança uma exceção… isso é um exemplo pratico, que me serve, e vc pode criar os seus…

Lavieri

PERFEITA A SUA EXPLICAÇÃO! Muito obrigado pela atenção cara… pude compreender muito melhor o conceito de interface agora… mesmo com esse seu exemplo do BoneSonzera :smiley:

Cara… obrigado de novo!!