Статический член класса - объявить класс закрытым, а член класса package-private? - PullRequest
5 голосов
/ 27 мая 2010

Считайте, что у вас есть следующий класс

public class OuterClass {
    ...

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

Мне кажется, я где-то читал (но не официальный Учебник по Java), что если бы я объявил атрибуты статических классов-членов частными, то компилятору пришлось бы генерировать какие-то методы доступа, чтобы внешний класс мог фактически получить доступ к статическому атрибуты класса-члена (который фактически является классом верхнего уровня, закрытым для пакета).

Есть идеи на этот счет?

Ответы [ 2 ]

4 голосов
/ 27 мая 2010

Да, это правда. По крайней мере, для Солнца Javac. Посмотрите на следующий пример:

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

}

Определяет static int access$002(int) для установки значения и static int access$000() для получения значения. Сеттер также возвращает значение, предположительно для легкой компиляции 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

}

В строке 2 и в строке 9 он вызывает сеттер (access$002) и геттер (access$000) соответственно.


Обратите внимание, что эти методы доступа доступны только в том случае, если они необходимы. Например, поле bar никогда не было доступно извне класса, поэтому компилятор генерировал только метод получения / установки для поля foo.

3 голосов
/ 27 мая 2010

Есть идеи на этот счет?

@ Ответ aioobe показывает, что вы были правы.

Однако, это, вероятно, не имеет значения. Скорее всего, JIT-компилятор встроит вызов метода доступа, и результирующий нативный код будет идентичен простой выборке. Даже если JIT-компилятор этого не делает, снижение производительности, скорее всего, будет незначительным в контексте приложения реального мира.

Это говорит о том, что бессмысленно преждевременно "оптимизировать" код с помощью модификаторов доступа, которые говорят что-то отличное от того, что вы действительно хотите выразить.

...