2010-05-27 11 views
5

trzeba rozważyć następujące klasyStatyczna klasa członków - zadeklaruj klasę prywatną i pakiet członkowski klasy-prywatny?

public class OuterClass { 
    ... 

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

myślę Czytałem gdzieś (ale nie oficjalnym Java Tutorial), że jeśli chciałbym zadeklarować statycznych klas członków atrybuty prywatne, kompilator musiał wygenerować jakąś metody uzyskiwania dostępu, aby klasa zewnętrzna mogła faktycznie uzyskać dostęp do statycznych klas członków (które są faktycznie pakietowymi prywatnymi klasami najwyższego poziomu).

Jakieś pomysły na ten temat?

Odpowiedz

4

Tak, to prawda. Przynajmniej dla javaca Słońca. Rzucić okiem na poniższy przykład:

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 

} 

Definiuje static int access$002(int) do ustawiania wartości, a static int access$000() uzyskania wartości. Setter zwraca również wartość, prawdopodobnie w celu łatwego skompilowania 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 

} 

w linii 2, a w linii 9 wywołuje ustawiającą (access$002) i pobierającą (access$000), odpowiednio.


Należy również pamiętać, że wprowadza tylko te metody dostępu, jeśli są potrzebne. Na przykład pole bar nigdy nie było dostępne spoza klasy, dlatego kompilator wygenerował tylko program pobierający/ustawiający dla pola foo.

+0

+1 Świetna odpowiedź. Więc czy zawsze powinieneś zadeklarować statyczną klasę członków private/package-private/protected i pozostawić pola członkowskie package-private? – helpermethod

+1

Metoda @Helper - Nie - zobacz moją odpowiedź. –

+0

Powinieneś zrobić to, co jest właściwe dla danego pola. Jeśli ma to sens, aby było prywatne, uczyń to prywatnym. Nie przejmuj się problemami z wydajnością itp., Dopóki nie ma to znaczenia, a następnie zaryzykuj program w całości i sprawdź, gdzie najlepiej wykorzystasz optymalizację. (Z całą pewnością nie będzie w takich przypadkach.) – aioobe

3

Jakieś pomysły na ten temat?

@ Odpowiedź Aioobe pokazuje, że masz rację.

Jednak prawdopodobnie nie ma znaczenia. Prawdopodobnie kompilator JIT wstawi wywołanie metody accessor, a wynikowy kod natywny będzie identyczny z prostym pobieraniem. Nawet jeśli kompilator JIT tego nie robi, kara za wydajność prawdopodobnie nie będzie znacząca w kontekście aplikacji realworld.

To, co mówi, to, że istnieje bez żadnego punktu przedwcześnie "optymalizując" kod za pomocą modyfikatorów dostępu, które mówią coś innego niż to, co naprawdę chcesz wyrazić.

Powiązane problemy