2011-05-10 17 views
11

Tengo dos unidades de compilación:Acceso a clase interna privada en el mismo paquete

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 "respuesta: testing123" se imprime. Si están en paquetes separados, se lanza IllegalAccessException.

Según tengo entendido, la excepción se produce 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 contra paquetes. Privado no debería ser visible fuera de OuterClass incluso si está en el mismo paquete. ¿Entiendo algo mal?

+0

La clase que ha llamado 'InnerClass' _no_ es una clase interna. 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 de 'InnerClass' y también el título de la pregunta. – mernst

Respuesta

8

El 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, el tiempo de ejecución) no hay tal cosa como 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.

modificadores de acceso reales se definen en el JVM spec:

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. 
-1

El modificador de acceso privado es más potente 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, son accesibles solo dentro de esa clase.

+0

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

+0

Parece que el sistema de reflexión lo permite por un motivo desconocido. Supongo que no sería posible con la invocación de método hard-coded. – Xion

+0

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 funciona en el bytecode resultante y no tiene conocimiento de nada que el compilador elimine. – McDowell

Cuestiones relacionadas