Pergunta

Desde que os genéricos foram introduzidos, Class é parametrizado, de modo que List.class produz Class<List>.Isto está claro.

O que não consigo descobrir é como obter uma instância de classe do tipo que é parametrizada, ou seja,Classe<Lista<String>>.Como neste trecho:

public class GenTest {
    static <T> T instantiate(Class<T> clazz) throws Exception {
        return clazz.newInstance();
    }
    public static void main(String[] args) throws Exception {
        // Is there a way to avoid waring on the line below
        // without using  @SuppressWarnings("unchecked")?
        // ArrayList.class is Class<ArrayList>, but I would like to
        // pass in Class<ArrayList<String>>
        ArrayList<String> l = GenTest.instantiate(ArrayList.class);
    }
}

Eu me deparo com variações desse problema com bastante frequência e ainda não sei se estou perdendo alguma coisa ou se realmente não há maneira melhor.Obrigado por sugestões.

Foi útil?

Solução

A classe Class é uma representação em tempo de execução de um tipo.Como os tipos parametrizados passam por apagamento de tipo em tempo de execução, o objeto de classe para Class seria o mesmo que para Class<List<Integer>> e Class<List<String>>.

A razão pela qual você não pode instanciá-los usando a notação .class é que esta é uma sintaxe especial usada para literais de classe.O Especificação da linguagem Java proíbe especificamente essa sintaxe quando o tipo é parametrizado, e é por isso que List<String>.class não é permitido.

Outras dicas

As classes representam classes carregadas por um carregador de classes, que são tipos brutos.Para representar um tipo parametrizado, use java.lang.reflect.ParameterizedType.

Eu não acho que você possa fazer o que está tentando.Em primeiro lugar, seu método de instanciação não sabe que está lidando com um tipo parametrizado (você poderia facilmente passá-lo java.util.Date.class).Em segundo lugar, devido ao apagamento, é difícil ou impossível fazer algo particularmente específico com tipos parametrizados em tempo de execução.

Se você abordar o problema de uma maneira diferente, existem outros pequenos truques que você pode fazer, como inferência de tipo:

public class GenTest
{
    private static <E> List<E> createList()
    {
        return new ArrayList<E>();
    }

    public static void main(String[] args)
    {
        List<String> list = createList();
        List<Integer> list2 = createList();
    }
}

A única coisa que você pode fazer é instanciar List<String> diretamente e chame seu getClass():

instantiate(new List<String>() { ... }.getClass());

Para tipos com vários métodos abstratos como List, isso é bastante estranho.Mas, infelizmente, chamar construtores de subclasses (como new ArrayList<String>) ou métodos de fábrica (Collections.<String>emptyList()) não funciona.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top