Ejemplo de código:

public class Foo
{
    public class Bar
    {
         public void printMesg(String body)
         {
             System.out.println(body);
         }
    }
    public static void main(String[] args)
    {
         //Creating new instance of 'Bar' using Class.forname - how?
    }        
}

Es posible crear una nueva instancia de la clase de la Barra dando su nombre? Traté de usar:

Class c = Class.forName("Foo$Bar")

se encuentra la clase, pero cuando yo uso c.newInstance() se lanza InstantiationException.

  • Pequeñeces: eso no es una clase anidada, es un miembro de la clase interna. Clases anidadas son estáticas, y fácilmente instanciado por el mecanismo de lo que tratamos.
  • ¿Cuáles fueron los detalles de la InstantiationException?
  • Las clases internas son un tipo de clase anidada (si no recuerdo JLS terminología correctamente).
  • Por goma de mascar, tienes razón… solo revisaba el JLS (java.sun.com/docs/books/jls/third_edition/html/…)…. «Una clase interna es una clase anidada que no está explícita o implícitamente declarado estática». Mi mal.
InformationsquelleAutor kars7e | 2010-01-19

7 Comentarios

  1. 54

    Que usted necesita para saltar a través de unos aros para ello. En primer lugar, usted necesita para utilizar Clase.getConstructor() para encontrar el Constructor objeto que desea invocar:

    Devuelve un objeto Constructor que
    refleja la pública especificado
    constructor de la clase representada
    por esta Clase de objetos. El
    parameterTypes parámetro es una matriz
    de los objetos de la Clase que identifique la
    constructor formal de los tipos de parámetros,
    en el declarado fin. Si esta Clase
    objeto representa una clase interna
    declaró en un no-estático contexto, la
    parámetro formal de los tipos de la
    explícito adjuntando instancia como la
    primer parámetro.

    Y, a continuación, utilizar Constructor.newInstance():

    Si el constructor de la clase declarante
    es una clase interna en un no-estático
    contexto, el primer argumento de la
    constructor debe ser que los envuelve
    ejemplo

    • Eso es lo que yo necesitaba. Gracias por la explicación completa!
    • Excelente explicación!
  2. 25

    Las clases internas pueden, de hecho, no se puede construir sin la construcción de los padres de clase primera. No puede existir fuera de la clase padre. Usted tendrá que pasar una instancia de la clase principal en cuando haciendo la reflexión. Clases anidadas son static y se pueden utilizar independientemente de la clase padre, así también cuando se hace la reflexión.

    He aquí un SSCCE que demuestra todas las cosas.

    package mypackage;
    
    import java.lang.reflect.Modifier;
    
    public class Parent {
    
        public static class Nested {
            public Nested() {
                System.out.println("Nested constructed");
            }
        }
    
        public class Inner {
            public Inner() {
                System.out.println("Inner constructed");
            }
        }
    
        public static void main(String... args) throws Exception {
            //Construct nested class the normal way:
            Nested nested = new Nested();
    
            //Construct inner class the normal way:
            Inner inner = new Parent().new Inner();
    
            //Construct nested class by reflection:
            Class.forName("mypackage.Parent$Nested").newInstance();
    
            //Construct inner class by reflection:
            Object parent = Class.forName("mypackage.Parent").newInstance();
            for (Class<?> cls : parent.getClass().getDeclaredClasses()) {
                if (!Modifier.isStatic(cls.getModifiers())) {
                    //This is an inner class. Pass the parent class in.
                    cls.getDeclaredConstructor(new Class[] { parent.getClass() }).newInstance(new Object[] { parent });
                } else {
                    //This is a nested class. You can also use it here as follows:
                    cls.getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {});
                }
            }
        }
    }

    Esto debe producir

    Anidada construido 
    Interior construido 
    Anidado construido 
    Interior construido 
    Anidado construido 
    
    • Excelente y completo ejemplo!
  3. 7

    Rápido y sucio código:

    Foo.Bar.class.getConstructors()[0].newInstance(new Foo());

    Explicación: debe indicar el Bar acerca de su adjuntando Foo.

    • Es sucio, pero es corto y funciona igual de bien :). Thx.
    • Que elude la mayor parte del problema como de la Barra no puede ser estática y/o puede incluso no ser visible…
    • Erm, mi respuesta se supone que la clase no es estática? Y si la clase fuera invisible OP obtendría un IllegalAccessException, no un InstantiationException …
  4. 2

    Sí. Recuerde que usted necesita para alimentar a la instancia exterior al interior de la clase. Uso javap para encontrar el constructor. Usted tendrá que ir a través de java.lang.reflect.Constructor en lugar de confiar en la maldad Class.newInstance.

    Compiled from "Foo.java"
    public class Foo$Bar extends java.lang.Object{
        final Foo this$0;
        public Foo$Bar(Foo);
        public void printMesg(java.lang.String);
    }

    javap -c es muy interesante, en el constructor porque (suponiendo -target 1.4 o más tarde, ahora implícito), se obtiene una asignación de un campo de instancia antes de llamar a la super constructor (que solía ser ilegal).

    public Foo$Bar(Foo);
      Code:
       0:   aload_0
       1:   aload_1
       2:   putfield        #1; //Field this$0:LFoo;
       5:   aload_0
       6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
       9:   return
    • yo nunca he escuchado acerca de javap antes. Thx por mostrarme que buena herramienta :).
  5. 1

    Otras respuestas han explicado cómo puede lo que quieres hacer.

    Pero quiero sugerir a usted que el hecho de que usted necesita hacer todo esto es una indicación de que hay algo mal con el diseño de su sistema. Me permito sugerir que usted necesita ya sea un (no estática) método de fábrica en la clase envolvente, o la necesidad de declarar la clase interna estática.

    La creación de una (no estática) interior de la instancia de la clase reflexiva tiene un «olor» de la rota de la encapsulación.

  6. 0

    Esto no es del todo óptimo, pero funciona para profundidades de las clases internas y el interior de las clases estáticas.

    public <T> T instantiateClass( final Class<T> cls ) throws CustomClassLoadException {
    try {
    List<Class<?>> toInstantiate = new ArrayList<Class<?>>();
    Class<?> parent = cls;
    while ( ! Modifier.isStatic( parent.getModifiers() ) && parent.isMemberClass() ) {
    toInstantiate.add( parent );
    parent = parent.getDeclaringClass();
    }
    toInstantiate.add( parent );
    Collections.reverse( toInstantiate );
    List<Object> instantiated = new ArrayList<Object>();
    for ( Class<?> current : toInstantiate ) {
    if ( instantiated.isEmpty() ) {
    instantiated.add( current.newInstance() );
    } else {
    Constructor<?> c = current.getConstructor( instantiated.get( instantiated.size() - 1 ).getClass() );
    instantiated.add( c.newInstance( instantiated.get( instantiated.size() - 1 ) ) );
    }
    }
    return (T) instantiated.get( instantiated.size() - 1 );
    } catch ( InstantiationException e ) {
    throw new CustomClassLoadException( "Failed to load class.", e );
    } catch ( IllegalAccessException e ) {
    throw new CustomClassLoadException( "Failed to load class.", e );
    } catch ( SecurityException e ) {
    throw new CustomClassLoadException( "Failed to load class.", e );
    } catch ( NoSuchMethodException e ) {
    throw new CustomClassLoadException( "Failed to load class.", e );
    } catch ( IllegalArgumentException e ) {
    throw new CustomClassLoadException( "Failed to load class.", e );
    } catch ( InvocationTargetException e ) {
    throw new CustomClassLoadException( "Failed to load class.", e );
    }
    }
  7. -1

    Aquí una respuesta para la clase anidada (interna estática):
    En mi caso necesito para adquirir el tipo por su nombre completo

    Class.forName(somePackage.innerClass$outerClass).getConstructor().newInstance();

    el ‘ $ » es crucial!

    con un punto obtendrá ClassNotFoundException para la clase «paquete.innerClass.outerClass». La excepción es missleading :-(.

    • Que no se compila, ni es el fin de innerClass$outerClass correcto…

Dejar respuesta

Please enter your comment!
Please enter your name here