5

考虑你有以下课程

public class OuterClass {
    ...

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

我想我在某处读过(但不是官方的 Java 教程),如果我将静态成员类属性声明为私有,编译器必须生成某种访问器方法,以便外部类可以实际访问静态成员类的 (这实际上是一个包私有的顶级类)属性。

有什么想法吗?

4

2 回答 2

4

是的,这是真的。至少对于 Sun 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)用于设置值的 a 和static int access$000()用于获取值的 a。setter 还返回值,大概是为了轻松 compile 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 行,它分别调用 setter ( access$002) 和 getter ( access$000)。


另请注意,它仅在需要时才引入这些访问器方法。例如,该bar字段从未从类外部访问过,因此编译器只为该foo字段生成了一个 getter/setter。

于 2010-05-27T10:32:23.710 回答
3

有什么想法吗?

@aioobe 的回答表明您是正确的。

但是,它可能没有任何区别。JIT 编译器可能会将对访问器方法的调用内联,并且生成的本机代码将与简单的 fetch 相同。即使 JIT 编译器不这样做,性能损失在实际应用程序的上下文中也可能微不足道。

这就是说,通过使用与您真正想要表达的内容不同的访问修饰符来过早地“优化”代码是没有意义的。

于 2010-05-27T10:43:19.160 回答