• Nenhum resultado encontrado

123Todos os direitos reservados a 3Way Networks

No documento Linguagem Java COMPLETA (páginas 123-125)

Linguagem de Programação Java

Seja um Profissional Aprendendo com Profissionais

www.3way.com.br 111

suficientemente adequada para qualquer tipo de animal:

jaulaAnimal = jaulaLeão; // erro compilação jaulaAnimal = jaulaBorboleta; // erro compilação

Sem generics os animais podem ser colocados em tipos inadequados de jaulas, de onde seria possível que eles escapassem.

9.5 Usando o Coringa <?>

Observe o exemplo import java.util.*; class Jaula<E> { private E animal; public Jaula() { } public E get() { return animal; }

public void add(E animal) { this.animal = animal; }

public void fill(List<Carnivoro> animais){

animais.add(new Cachorro()); // Ok,adiciona um Cachorro de //subtipo Carnivoro

} }

Listagem 9.5 – Nova Jaula com método que Lista de carnivoros public class JaulaDemo {

public static void main(String[] args) {

List<Cachorro> listaCachorro = new ArrayList<Cachorro>(); listaCachorro.add(new Cachorro());

listaCachorro.add(new Cachorro());

Jaula<Carnivoro> jaula = new Jaula<Carnivoro>();

jaula.fill(listaCachorro); //Erro,esperava List<Carnivoro> //foi passado List<Cachorro> }

}

Listagem 9.6 – Testa Jaula

O compilador vai emitir a seguinte mensagem (Listagem 9.6, linha 8),

The method fill(List<Carnivoro>) in the type Jaula<Carnivoro> is not applicable for the arguments (List<Cachorro>)

Este erro de compilação é igual ao que ocorre a um método qualquer, que receba como argumento uma referência de tipo diferente do tipo do parâmetro definido na assinatura do método. Ou seja, como visto anteriormente (seção 9.5), List<Cachorro> não é subtipo de List<Carnivoro>. Mas o que pesa neste exemplo é que,

//atribuindo valor a variável referência Carro carro1 = new Carro();

carro1.ano = "2001"; carro1.modelo= "fusca"; carro1.cor = "prata";

Figura 2.4 – Layout Memória após inicialização //criando novo alias

Carro carro2 = carro1;

Figura 2.5 – Layout Memória duas variáveis referência para o mesmo objeto

2.3 Membros de Instância

Cada objeto criado deverá ter sua própria instância de variáveis (atributos) definidas pela classe. Os métodos definem o comportamento de um objeto. Isto é importante, pois denota que um método pertence a cada objeto da classe. Porém não devemos confundir isto com a implementação do método, que é compartilhada por todas as instâncias da classe.

2.3.1 Invocação de Métodos

Objetos se comunicam pela troca de mensagens, isto significa que um objeto pode ter que mostrar um comportamento particular invocando uma operação apropriada que foi definida no objeto. Em Java, isto é feito pela

chamada de um método em um objeto usando o operador binário "." (ponto),

devendo especificar a mensagem completa: o objeto que é o recebedor da mensagem, o método a ser invocado e os argumentos para o método (se houver). O método invocado no recebedor pode também enviar informações de volta ao objeto chamador através de um valor de retorno. O método chamado deve ser um que esteja definido pelo objeto.

Os valores das variáveis em um objeto constituem

o seu estado. Dois objetos distintos têm

o mesmo estado se suas variáveis membro têm os

mesmos valores. com genérics, parece que perdemos o que havia de melhor em Java, o polimorfismo de referência. O que você deve observar é que a notação de genéricos nos obriga a trabalhar com um único tipo, não nos deixando manipular os métodos sobrepostos nas subclasses a partir de referências do tipo da superclasse, como vimos ser possível ao estudarmos polimorfismo, sem generics.

Para continuarmos com a segurança de tipo, trazida por generics, e ainda termos o nosso aclamado comportamento polimórfico, precisamos de uma maneira de dizer ao compilador que desejamos usar qualquer subtipo genérico do tipo do argumento declarado. Felizmente podemos utilizar o literal <?>, o coringa, como forma de dizer ao compilador que o método aceita qualquer tipo, ou ainda <? extends AlgumaClasse>, para dizer que qualquer objeto do tipo da classe ou de suas subclasses serão aceitos.

Vejamos nosso exemplo modificado:

public class Jaula<T> { private T animal; public Jaula() { } public T get() { return animal; }

public void add(T animal) { this.animal = animal; }

public void fill(List<? extends Carnivoro> listaCanivoros){ listaCanivoros.add(new Cachorro());//ERRO

} }

Listagem 9.7 – Usado o coringa public class JaulaDemo {

public static void main(String[] args) {

List<Cachorro> listaCachorro = new ArrayList<Cachorro>(); listaCachorro.add(new Cachorro());

listaCachorro.add(new Cachorro());

Jaula<Carnivoro> jaula = new Jaula<Carnivoro>();

jaula.fill(listaCachorro);//ok, Cachorro extends Carnivoro }

}

Listagem 9.8– Testa Jaula com argumento coringa

Nosso problema agora é o método add(E o) (Listagem 9.7, linha 15), de List. O método add(), em sua definição exige que o argumento deve ter o mesmo tipo utilizado por List, mas o problema reside justamente no fato de que o argumento pode ser de qualquer tipo ou subtipo da classe Carnivoro, assim add() se recusa a adicionar algo desconhecido e que possa causar algum problema. Esse é o preço a ser pago pelo benefício de uma tipagem segura (previsível em tempo de compilação) e de podermos invocar qualquer métodos polimórfico. Você terá que aceitar o fato de seu método fill() só poderá fazer leitura. Reescrevendo o exemplo,

public class Jaula<T> { private T animal; public Jaula() { } Quando utilizamos <?>, sem extends estamos dizendo <? extends Object>, ou seja qualquer objeto.

Linguagem de Programação Java

Seja um Profissional Aprendendo com Profissionais

www.3way.com.br 12

//atribuindo valor a variável referência Carro carro1 = new Carro();

carro1.ano = "2001"; carro1.modelo= "fusca"; carro1.cor = "prata";

Figura 2.4 – Layout Memória após inicialização //criando novo alias

Carro carro2 = carro1;

Figura 2.5 – Layout Memória duas variáveis referência para o mesmo objeto

2.3 Membros de Instância

Cada objeto criado deverá ter sua própria instância de variáveis (atributos) definidas pela classe. Os métodos definem o comportamento de um objeto. Isto é importante, pois denota que um método pertence a cada objeto da classe. Porém não devemos confundir isto com a implementação do método, que é compartilhada por todas as instâncias da classe.

2.3.1 Invocação de Métodos

Objetos se comunicam pela troca de mensagens, isto significa que um objeto pode ter que mostrar um comportamento particular invocando uma operação apropriada que foi definida no objeto. Em Java, isto é feito pela

chamada de um método em um objeto usando o operador binário "." (ponto),

devendo especificar a mensagem completa: o objeto que é o recebedor da mensagem, o método a ser invocado e os argumentos para o método (se houver). O método invocado no recebedor pode também enviar informações de volta ao objeto chamador através de um valor de retorno. O método chamado deve ser um que esteja definido pelo objeto.

Os valores das variáveis em um objeto constituem

o seu estado. Dois objetos distintos têm

o mesmo estado se suas variáveis membro têm os

mesmos valores.

125

No documento Linguagem Java COMPLETA (páginas 123-125)

Documentos relacionados