JVM 字节码访问修饰符标志 0x1000(十六进制)何时是“合成的”?放?
对于某些 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
的用途。我在内部类中看到过一次,但是对于从那时起我检查过的所有内部类,这个标志从未设置过。您现在知道该标志的含义是什么以及它在何处/何时设置?
For some Java byte code parser project I read the JVM spec and figured out that the bit mask values of the Java virtual machine class file format access modifier fields are
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
Somehow I have no idea what 0x1000
is for. I saw it once in an inner class, but for all inner classes I checked since then, this flag was never set. Do you now what the meaning of this flag is and where/when it is set?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
合成元素是存在于编译的类文件中但不存在于编译它的源代码中的任何元素。通过检查某个元素是否是合成的,您可以区分这些元素以用于反射处理代码的工具。这当然首先与使用反射的库相关,但也与其他工具(例如 IDE)相关,这些工具不允许您调用合成方法或使用合成类。最后,对于 Java 编译器来说,在编译期间验证代码不要直接使用合成元素也很重要。合成元素仅用于使 Java 运行时满意,它只是处理(并验证)交付的代码,其中合成元素与任何其他元素的处理方式相同。
您已经提到了内部类作为 Java 编译器插入合成元素的示例,所以让我们看一下这样一个类:
它编译得很好,但如果没有合成元素,它会被一个不知道任何东西的 JVM 拒绝内部类。 Java 编译器将上述类转换为如下内容:
如前所述,JVM 不知道内部类,但强制执行成员的私有访问,即内部类将无法访问其封闭的类类的私有属性。因此,Java 编译器需要向被访问的类添加所谓的访问器,以便公开其不可见属性:
foo
字段是私有的,因此只能从 <代码>Foo。access$100
方法将此字段公开给其包,在该包中始终可以找到内部类。此方法是合成方法,因为它是由编译器添加的。Bar
构造函数是私有的,因此只能从其自己的类中调用。为了实例化 Bar 的实例,另一个(合成)构造函数需要公开实例的构造。然而,构造函数有一个固定的名称(在内部,它们都被称为
),因此我们不能将这种技术应用于方法访问器,我们只是将它们命名为access$xxx
>。相反,我们通过创建合成类型Foo$1
使构造函数访问器变得唯一。为了访问其外部实例,内部类需要存储对此实例的引用,该引用存储在合成字段
$this
中。该引用需要通过构造函数中的合成参数传递给内部实例。合成元素的其他示例包括表示 lambda 表达式的类、使用不同类型签名重写方法时的桥接方法、创建 Proxy 类或由 Maven 构建或运行时代码等其他工具创建的类诸如 Byte Buddy(无耻插件)之类的生成器。
A synthetic element is any element that is present in a compiled class file but not in the source code it is compiled from. By checking an element for it being synthetic, you allow a distinction of such elements for tools that process code reflectively. This is of course first of all relevant to libraries that use reflection but it is also relevant for other tools like IDEs that do not allow you to call synthetic methods or to work with synthetic classes. Finally, it is also important for the Java compiler to verify code during its compilation to never directly use synthetic elements. Synthetic elements are only used to make the Java runtime happy which simply processes (and verifies) the delivered code where it treats synthetic elements identically to any other element.
You already mentioned inner classes as an example where synthetic elements are inserted by the Java compiler, so let us look at such a class:
This compiles perfectly fine but without synthetic elements, it would be refused by a JVM that does not know a thing about inner classes. The Java compiler desugares the above class to something like the following:
As said, the JVM does not know about inner classes but enforces private access of members, i.e. an inner class would not be able to access its enclosing classes' private properties. Thus, the Java compiler needs to add so-called accessors to an accessed class in order to expose its non-visible properties:
The
foo
field is private and can therefore only be accessed from withinFoo
. Theaccess$100
method exposes this field to its package in which an inner class is always to be found. This method is synthetic as it is added by the compiler.The
Bar
constructor is private and can therefore only be called from within its own class. In order to instantiate an instance ofBar
, another (synthetic) constructor needs to expose the construction of an instance. However, constructors have a fixed name (internally, they are all called<init>
), thus we cannot apply the technique for method accessors where we simply named themaccess$xxx
. Instead, we make constructor accessors unique by creating a synthetic typeFoo$1
.In order to access its outer instance, an inner class needs to store a reference to this instance which is stored in a synthetic field
$this
. This reference needs to be handed to the inner instance by a synthetic parameter in the constructor.Other examples for synthetic elements are classes that represent lambda expressions, bridge methods when overriding methods with a type-divergent signatures, the creation of
Proxy
classes or classes that are created by other tools like Maven builds or runtime code generators such as Byte Buddy (shameless plug).它是“合成”标志,在编译器生成字段或方法时设置。 AFAIK 它用于内部类,它与您的观察相一致,并且当工件没有出现在源代码中时必须设置。
http://java.sun.com/docs /books/jvms/second_edition/html/ClassFile.doc.html#88571
It's the "synthetic" flag, set when the field or method is generated by the compiler. AFAIK it's for inner classes, which meshes with your observation, and must be set when an artifact doesn't appear in the source code.
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88571