2010-05-27 40 views
5

Considere usted tiene la siguiente claseClase de miembro estático: ¿declara clase privada y miembro de clase paquete privado?

public class OuterClass { 
    ... 

    private static class InnerClass { 
     int foo; 
     int bar; 
    } 
} 

Creo que he leído en alguna parte (pero no el tutorial de Java oficial) que si los anunciara, las clases miembro estáticas atributos privada, el compilador tuvo que generar algún tipo de métodos de acceso para que la clase externa pueda acceder realmente a los atributos de la clase de miembro estática (que es efectivamente un paquete de nivel superior privado).

¿Alguna idea sobre eso?

Respuesta

4

Sí, eso es cierto. Al menos para el Sun javac. Echar un vistazo al siguiente ejemplo:

public class OuterClass { 

    public static void main(String... args) { 
     InnerClass.foo = 7; 
     System.out.println(InnerClass.foo); 
    } 

    private static class InnerClass { 
     private static int foo; 
     private static int bar; 
    } 
} 

$ javap -c OuterClass\$InnerClass 
Compiled from "OuterClass.java" 
class OuterClass$InnerClass extends java.lang.Object{ 
static int access$002(int); 
    Code: 
    0: iload_0 
    1: dup 
    2: putstatiC#1; //Field foo:I 
    5: ireturn 

static int access$000(); 
    Code: 
    0: getstatiC#1; //Field foo:I 
    3: ireturn 

} 

Se define un static int access$002(int) para ajustar el valor, y una static int access$000() para obtener el valor. El colocador también devuelve el valor, presumiblemente para compilar fácilmente someVariable = InnerClass.foo = 5.


$ javap -c OuterClass 
Compiled from "OuterClass.java" 
public class OuterClass extends java.lang.Object{ 
public OuterClass(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."<init>":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: bipush 7 
    2: invokestatiC#2; //Method OuterClass$InnerClass.access$002:(I)I 
    5: pop 
    6: getstatiC#3; //Field java/lang/System.out:Ljava/io/PrintStream; 
    9: invokestatiC#4; //Method OuterClass$InnerClass.access$000:()I 
    12: invokevirtual #5; //Method java/io/PrintStream.println:(I)V 
    15: return 

} 

En la línea 2 y en la línea 9 que llama el setter (access$002) y getter (access$000) respectivamente.


Tenga en cuenta que solo presenta estos métodos de acceso si son necesarios. El campo bar, por ejemplo, nunca fue accedido desde fuera de la clase, por lo tanto, el compilador solo generó un getter/setter para el campo foo.

+0

+1 Gran respuesta. Entonces, ¿siempre debe declarar la clase de miembro estática private/package-private/protected y dejar los campos de miembro package-private? – helpermethod

+1

@Helper Method - No - ve mi respuesta. –

+0

Debe hacer lo que sea apropiado para el campo en cuestión. Si tiene sentido que sea privado, hazlo privado. No se preocupe por los problemas de rendimiento, etc., hasta que sea importante, y luego perfile el programa en su totalidad y vea dónde obtiene la optimización al máximo. (Ciertamente no será en casos como estos). – aioobe

3

¿Alguna idea de eso?

@ aioobe contesta que estás en lo cierto.

Sin embargo, probablemente no hace ninguna diferencia. Lo más probable es que el compilador JIT alinee la llamada al método de acceso y el código nativo resultante será idéntico a un acceso simple. Incluso si el compilador JIT no hace eso, es probable que la penalización del rendimiento sea insignificante en el contexto de una aplicación del mundo real.

Lo que esto dice es que hay sin punto prematuramente "optimizando" el código mediante el uso de modificadores de acceso que dicen algo diferente a lo que realmente desea expresar.

Cuestiones relacionadas