Pergunta

Eu tenho um método de utilitário e quando a lógica irrelevante é removido a partir dele, o método simplificado ficaria assim:

public static <A extends Foo> List<A> getFooList(Class<A> clazz) {
   List<A> returnValue = new ArrayList<A>();
   for(int i=0; i < 5; i++) {
        A object = clazz.newInstance();
        returnValue.add(object);
   }

   return returnValue;
}

O problema é que, se clazz é uma classe interna, como Foo.Bar.class, então o método newInstance() não vai funcionar mesmo se Bar seria pública, uma vez que irá lançar um java.lang.InstantiationException.

Existe uma maneira de classes internas dinamicamente instanciar?

Foi útil?

Solução

Se é realmente um interior classe em vez de uma classe aninhada (estático), há um parâmetro de construtor implícito, que é a referência para a instância da classe externa. Você não pode usar Class.newInstance nessa fase - você tem que obter o construtor apropriado. Aqui está um exemplo:

import java.lang.reflect.*;

class Test
{
    public static void main(String[] args) throws Exception
    {
        Class<Outer.Inner> clazz = Outer.Inner.class;

        Constructor<Outer.Inner> ctor = clazz.getConstructor(Outer.class);

        Outer outer = new Outer();
        Outer.Inner instance = ctor.newInstance(outer);
    }
}

class Outer
{
    class Inner
    {
        // getConstructor only returns a public constructor. If you need
        // non-public ones, use getDeclaredConstructors
        public Inner() {}
    }
}

Outras dicas

Algo mais genérico:

    public static <T> T createInstance(final Class<T> clazz) throws SecurityException, NoSuchMethodException,
            IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {

            T instanceToReturn = null;
            Class< ? > enclosingClass = clazz.getEnclosingClass();

            if (enclosingClass != null) {
                Object instanceOfEnclosingClass = createInstance(enclosingClass);

                Constructor<T> ctor = clazz.getConstructor(enclosingClass);

                if (ctor != null) {
                    instanceToReturn = ctor.newInstance(instanceOfEnclosingClass);
                }
            } else {
                instanceToReturn = clazz.newInstance();
            }

            return instanceToReturn;
     }

Esta exceção será lançada somente se clazz representa ou uma classe abstrata ou uma interface. Tem certeza de que você está passando um objeto de classe que representa uma classe concreta?

Em JMockit 1,41, use o seguinte:

ConstructorReflection.newInstance

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