Accediendo a la clase interna privada en el mismo paquete

Tengo dos unidades de compilación:

public class OuterClass{

    private static class InnerClass{

        public String test(){
            return "testing123";
        }
    }

    public static void main( String[] args ){
        new CallingClass().test( new InnerClass() );
    }
}


public class CallingClass{

    public void test( Object o ){
        try{
            Method m = o.getClass().getMethod( "test" );
            Object response = m.invoke( o );
            System.out.println( "response: " + response );
        }
        catch( Exception e ){
            e.printStackTrace();
        }
    }
}

Si están en el mismo paquete, todo funciona y se imprime "response: testing123". Si están en paquetes separados, se lanza IllegalAccessException.

Según tengo entendido, se lanza una excepción porque CallingClass no puede invocar métodos privados de InnerClass. Pero lo que no entiendo es por qué está permitido en el mismo paquete. InnerClass no está protegido por paquetes. Private no debe ser visible fuera de OuterClass incluso si está en el mismo paquete. ¿Entiendo algo mal?

preguntado el 10 de mayo de 11 a las 13:05

La clase que has nombrado InnerClass is no es una clase interior. En realidad, es una clase anidada estática. (En Java, las clases anidadas son de dos variedades: estática e interna). Ha planteado una buena pregunta, pero no tiene nada que ver con las clases internas, por lo que le sugiero que cambie el nombre InnerClass y también el título de la pregunta. -

2 Respuestas

La javap firma para una clase interna:

class modifiers.OuterClass$InnerClass extends java.lang.Object{
    final modifiers.OuterClass this$0;
    public java.lang.String test();
}

Cuando se trata de código de bytes (es decir, tiempo de ejecución), no existe una clase privada. Esta es una ficción mantenida por el compilador. Para la API de reflexión, hay un tipo de paquete accesible con un método de miembro público.

Los modificadores de acceso reales se definen en el Especificaciones de JVM:

Flag Name      Value   Interpretation
ACC_PUBLIC     0x0001  Declared public; may be accessed from outside its package.
ACC_FINAL      0x0010  Declared final; no subclasses allowed.
ACC_SUPER      0x0020  Treat superclass methods specially when invoked by the
                       invokespecial instruction.
ACC_INTERFACE  0x0200  Is an interface, not a class.
ACC_ABSTRACT   0x0400  Declared abstract; may not be instantiated. 

contestado el 10 de mayo de 11 a las 19:05

El modificador de acceso privado es más fuerte que el paquete uno (es decir, no tiene ningún modificador de acceso en Java). Por lo tanto, los elementos privados de la clase, ya sean campos, métodos o clases internas, solo son accesibles dentro de esa clase.

contestado el 10 de mayo de 11 a las 18:05

Tienes razón. ¿Pero entonces por qué puedo acceder a él fuera de la clase? - martsraits

Parece que el sistema de reflexión lo permite por una razón desconocida. Supongo que no sería posible con la invocación de métodos codificados. - Xion

Esta respuesta no es del todo precisa. El lenguaje Java (y sus compiladores) crean algunas ilusiones que no se mantienen después de la compilación. La API de reflexión opera en el código de bytes resultante y no es consciente de nada que sea barrido por el compilador. - McDowell

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.