2010-05-27 9 views
5

Considérez vous avez la classe suivanteClasse de membre statique - déclarez la classe private et le membre de classe package-private?

public class OuterClass { 
    ... 

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

Je pense que je l'ai lu quelque part (mais pas le Java Tutorial officiel) que si je déclarerais les classes membres statiques attributs privés, le compilateur devait générer une sorte de méthodes d'accès pour que la classe externe puisse réellement accéder aux attributs de la classe membre statique (qui est effectivement une classe de niveau supérieur privé-paquet).

Des idées là-dessus?

Répondre

4

Oui, c'est vrai. Au moins pour le javac de Sun. Jetez un oeil à l'exemple suivant:

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 

} 

Il définit un static int access$002(int) pour régler la valeur, et un static int access$000() pour obtenir la valeur. Le setter renvoie également la valeur, vraisemblablement pour compiler facilement 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 

} 

A la ligne 2 et à la ligne 9, il appelle le dispositif de réglage (access$002) et getter (access$000), respectivement.


Notez également qu'il introduit uniquement ces méthodes d'accès si elles sont nécessaires. Le champ bar, par exemple, n'a jamais été accédé depuis l'extérieur de la classe, ainsi le compilateur n'a généré qu'un getter/setter pour le champ foo.

+0

+1 Bonne réponse. Donc, devriez-vous toujours déclarer la classe membre static private/package-private/protected et laisser les champs membres package-private? – helpermethod

+1

@Helper Méthode - Non - voir ma réponse. –

+0

Vous devriez faire ce qui est approprié pour le domaine en question. S'il est logique de l'avoir privé, rendez-le privé. Ne vous inquiétez pas des problèmes de performances, etc., jusqu'à ce que cela soit important, puis mettez en profil le programme dans son intégralité et voyez où vous en tirez le meilleur parti. (Il ne sera certainement pas dans des cas comme ceux-ci.) – aioobe

3

Des idées là-dessus?

La réponse de @ aioobe montre que vous étiez correct.

Cependant, cela ne fait probablement pas de différence. Les probabilités sont que le compilateur JIT alignera l'appel à la méthode accesseur et le code natif résultant sera identique à un simple fetch. Même si le compilateur JIT ne le fait pas, la pénalité de performance risque d'être insignifiante dans le contexte d'une application realworld. Cela signifie qu'il y a aucun point "optimisation" prématurée du code en utilisant des modificateurs d'accès qui disent quelque chose de différent de ce que vous voulez vraiment exprimer.

Questions connexes