什么时候JVM字节码访问修饰符标志0x1000(十六进制)“合成”设置?

时间:2011-12-16 22:14:30

标签: java bytecode access-modifiers .class-file

对于某些Java字节代码解析器项目,我读了JVM规范,并发现Java虚拟机类文件格式访问修饰符字段的位掩码值是

  ACC_PUBLIC = 0x0001
  ACC_FINAL = 0x0010
  ACC_SUPER = 0x0020 # old invokespecial instruction semantics (Java 1.0x?)
  ACC_INTERFACE = 0x0200
  ACC_ABSTRACT = 0x0400
  ACC_SYNTHETIC = 0x1000 
  ACC_ANNOTATION = 0x2000
  ACC_ENUM = 0x4000

不知怎的,我不知道0x1000是什么。我在内部类中看到过一次,但是从那时起我检查了所有内部类,这个标志从未设置过。你现在知道这个标志的含义是什么,设置在何处/何时?

2 个答案:

答案 0 :(得分:9)

合成元素是编译的类文件中存在的任何元素,但不是编译它的源代码中的元素。通过检查元素是否为合成元素,可以将这些元素区分为可反复处理代码的工具。这当然首先与使用反射的库相关,但它也与IDE之类的其他工具相关,这些工具不允许您调用合成方法或使用合成类。最后,Java编译器在编译期间验证代码永远不会直接使用合成元素也很重要。合成元素仅用于使Java运行时满意,它简单地处理(和验证)交付的代码,其中合成元素与任何其他元素相同。

您已经提到内部类作为Java编译器插入合成元素的示例,所以让我们看一下这样的类:

class Foo {

  private String foo;

  class Bar {

    private Bar() { }

    String bar() {
      return foo;
    }
  }

  Bar bar() {
    return new Bar();
  }
}

这个编译非常精细但没有合成元素,它会被一个不了解内部类的JVM拒绝。 Java编译器将上面的类看作以下类似的内容:

class Foo {

  private String foo;

  String access$100() {  // synthetic method
    return foo;
  }

  Foo$Bar bar() {
    return new Foo$Bar(this, (Foo$1)null);
  }

  Foo() { } // NON-synthetic, but implicit!
}

class Foo$Bar {

  private final Foo $this; // synthetic field

  private Foo$Bar(Foo $this) {  // synthetic parameter
    this.$this = $this;
  }

  Foo$Bar(Foo $this, Foo$1 unused) {  // synthetic constructor
    this($this);
  }

  String bar() {
    return $this.access$100();
  }
}

class Foo$1 { /*empty, no constructor */ } // synthetic class

如上所述,JVM不了解内部类,但强制成员的私有访问,即内部类无法访问其封闭的类'私人财产。因此,Java编译器需要向被访问的类添加所谓的访问器,以便公开其不可见的属性:

  1. foo字段是私有的,因此只能在Foo内访问。 access$100方法将此字段公开给其中始终要找到内部类的包。此方法是合成的,因为它是由编译器添加的。

  2. Bar构造函数是私有的,因此只能在其自己的类中调用。为了实例化Bar的实例,另一个(合成)构造函数需要公开实例的构造。但是,构造函数具有固定的名称(在内部,它们都被称为<init>),因此我们不能将该技术应用于我们只是将它们命名为access$xxx的方法访问器。相反,我们通过创建合成类型Foo$1来使构造函数访问器成为唯一的。

  3. 为了访问其外部实例,内部类需要存储对此实例的引用,该引用存储在合成字段$this中。此引用需要通过构造函数中的合成参数传递给内部实例。

  4. 合成元素的其他示例是表示lambda表达式的类,使用类型 - 发散签名覆盖方法时的桥接方法,由Maven构建或运行时代码等其他工具创建的Proxy类或类的创建诸如Byte Buddy之类的生成器(无耻插件)。

答案 1 :(得分:3)

它是“synthetic”标志,在编译器生成字段或方法时设置。 AFAIK用于内部类,与您的观察相结合,并且必须在源代码中未出现工件时设置。

http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88571