27

我正在查看一些从 Java 字节码获得的反汇编代码。我看到一些声明如下:

.method static synthetic access$0()Lcom/package/Sample;

我无法弄清楚syntheticor是什么access$0意思。有人可以帮我理解这部分吗?

4

3 回答 3

33

在 Java 语言中,内部类可以访问其封闭类的私有成员。但是在Java字节码中,不存在内部类的概念,私有成员是不可访问的。为了解决这个问题,编译器在外部类中创建合成访问器方法。我相信这就是你在这里看到的。access$0只是方法的名称。我不确定是什么,如果有的话synthetic。它可能只是对其他编译器隐藏该方法以确保封装。

于 2011-03-07T18:08:30.163 回答
28

合成领域(2)

将本地内部类链接到块的本地变量或引用类型参数的编译器创建的字段。

另请参见 Java 中The JavaTM Virtual Machine Specification (§4.7.6)合成类

于 2011-03-07T18:04:04.247 回答
4

assert声明 JDK 1.8 案例研究

该语句是在 Oracle JDK 1.8.0_45assert中生成字段的构造示例:static synthetic

public class Assert {
    public static void main(String[] args) {
        assert System.currentTimeMillis() == 0L;
    }
}

基本上编译为:

public class Assert {
    // This field is synthetic.
    static final boolean $assertionsDisabled =
        !Assert.class.desiredAssertionStatus();
    public static void main(String[] args) {
        if (!$assertionsDisabled) {
            if (System.currentTimeMillis() != 0L) {
                throw new AssertionError();
            }
        }
    }
} 

这可以通过以下方式验证:

javac Assert.java
javap -c -constants -private -verbose Assert.class

其中包含:

    static final boolean $assertionsDisabled;
  descriptor: Z
  flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC

生成合成字段,以便 Java 只需要Assert.class.desiredAssertionStatus()在加载时调用一次,然后将结果缓存在那里。

另请参阅:https ://stackoverflow.com/a/29439538/895245以获得更详细的说明。

请注意,此合成字段可能会与我们可能定义的其他字段产生名称冲突。例如,以下在 Oracle JDK 1.8.0_45 上编译失败:

public class Assert {
    static final boolean $assertionsDisabled = false;
    public static void main(String[] args) {
        assert System.currentTimeMillis() == 0L;
    }
}

唯一“阻止”的是在标识符上不使用美元的命名约定。另请参阅:何时应在变量名中使用美元符号 ($)?

奖金:

static final int $assertionsDisabled = 0;

会起作用,因为与 Java 不同,字节码允许具有相同名称但类型不同的多个字段:具有相同名称但类型不同的变量

于 2015-07-11T08:54:59.363 回答