Generics

7 respostas
G

Olá Galera,

package Generics;

import java.util.*;


public class Declare{

	public static void main(String[] args){
		List l = new ArrayList();
		//List<Object> l1 = new ArrayList<String>();
		test(l); 
	}

	public static void test(List<String> list){list.add("5");}

}

Alguém me explica porque é possível passar um List (sem uso de generic) para um método que usa Generic?

[]s
Gunnar

7 Respostas

T

É possível sim, mas dá aqueles warnings.

É que, diferentemente do .NET, os “generics” são construídos usando-se “erasure”, e basicamente (se você for analisar o código gerado pelo compilador) são uma forma complicada de pôr os “casts” corretos nos lugares certos.

Então você pode até chamar uma biblioteca Java antiga (1.4 ou anterior) sem ter o fonte, só o .jar ou .class, e ela funcionar perfeitamente, ou vice-versa, porque um ArrayList<String> é só um ArrayList antigo, mas com os casts acrescentados automaticamente pelo compilador.

saoj

Outra coisa que vc não vai conseguir fazer com Generics é instanciar via reflection um ArrayList<String>. Isso é impossível em Java. Não sei se em NET é possível… (Eu adoraria descobrir que estou enganado aqui…)

G

thingol:
É possível sim, mas dá aqueles warnings.

É que, diferentemente do .NET, os “generics” são construídos usando-se “erasure”, e basicamente (se você for analisar o código gerado pelo compilador) são uma forma complicada de pôr os “casts” corretos nos lugares certos.

Então você pode até chamar uma biblioteca Java antiga (1.4 ou anterior) sem ter o fonte, só o .jar ou .class, e ela funcionar perfeitamente, ou vice-versa, porque um ArrayList<String> é só um ArrayList antigo, mas com os casts acrescentados automaticamente pelo compilador.

Mas do jeito que eu entendo o compilador verificaria o “tipo” do objeto que você esta passando para o método e o tipo que o método espera receber, compararia os dois e em caso de não serem iguais, daria um erro.

R

gk-bgh:

Mas do jeito que eu entendo o compilador verificaria o “tipo” do objeto que você esta passando para o método e o tipo que o método espera receber, compararia os dois e em caso de não serem iguais, daria um erro.

Isso poderia ser feito, mas quebraria todos os códigos existentes nas versões anteriores. E, por uma decisão de projeto da linguagem, decidiram que isso não daria erro de compilação e apenas emitiria um warning (avisao, alerta, etc.).

G

RafaelVS:
gk-bgh:

Mas do jeito que eu entendo o compilador verificaria o “tipo” do objeto que você esta passando para o método e o tipo que o método espera receber, compararia os dois e em caso de não serem iguais, daria um erro.

Isso poderia ser feito, mas quebraria todos os códigos existentes nas versões anteriores. E, por uma decisão de projeto da linguagem, decidiram que isso não daria erro de compilação e apenas emitiria um warning (avisao, alerta, etc.).

Não estou entendendo pelo seguinte…
porque o compilador não aceita passar um ArrayList<Object> para um método que aceita ArrayList<String> mas aceita passar um ArrayList para um método que aceita ArrayList<String>. Se fosse o type erasure o primeiro caso funcionaria, não?

[]s
Gunnar

T

O “generics” só funciona direito se você olhar todos os warnings e não deixar escapar nenhum.
No seu caso, você tentou passar um ArrayList para um método que requer um ArrayList<String> .
Um warning vai ser gerado, dizendo que ele não garante que realmente haja strings nesse arraylist de strings.
Vou dar um exemplo em que há um warning e então ocorre um ClassCastException em tempo de execução:

import java.util.*;
/**
TesteMauUsoDeGenerics.java:14: warning: [unchecked] unchecked call to add(E) as
a member of the raw type java.util.List
        inteiros.add (3);
                     ^
TesteMauUsoDeGenerics.java:15: warning: [unchecked] unchecked call to add(E) as
a member of the raw type java.util.List
        inteiros.add (20);
                     ^
TesteMauUsoDeGenerics.java:16: warning: [unchecked] unchecked call to add(E) as
a member of the raw type java.util.List
        inteiros.add ("Abobrinha");
                     ^
TesteMauUsoDeGenerics.java:17: warning: [unchecked] unchecked conversion
found   : java.util.List
required: java.util.List&lt;java.lang.String&gt;
        t.processarListaString (inteiros);
                                ^
4 warnings
*/
class TesteMauUsoDeGenerics {
    public String processarListaString (List&lt;String&gt; strings) {
        StringBuffer sb = new StringBuffer();
        for (Iterator&lt;String&gt; iter = strings.iterator(); iter.hasNext(); ) {
            sb.append (iter.next()); // vai ocorrer um ClassCastException aqui no primeiro item da 

lista
        }
        return sb.toString();
    }
    public static void main(String[] args) {
        TesteMauUsoDeGenerics t = new TesteMauUsoDeGenerics();
        List inteiros = new ArrayList&lt;Integer&gt;();
        inteiros.add (3); //-&gt; warning
        inteiros.add (20); //-&gt; warning
        inteiros.add ("Abobrinha"); //-&gt; warning
        t.processarListaString (inteiros); //-&gt; warning : [unchecked] unchecked conversion
    }
}
R

ArrayList para um método que aceita ArrayList acho que não deveria ser permitido (como de fato não é) ja que nem todo Object é String.

Pensando o contrário ArrayList para um método que aceita ArrayList, conceitualmente falando, Java permite isso, porém a sintaxe é diferente. Seria ArrayList para um método que aceita ArrayList<? extends Object>.

Criado 14 de novembro de 2007
Ultima resposta 14 de nov. de 2007
Respostas 7
Participantes 4