简体   繁体   English

Java 中的符号引用

[英]Symbolic references in Java

In these days I have been playing with Java reflection and .class format.这些天我一直在玩 Java 反射和.class格式。 I'm currently studying ldc instruction.我目前正在学习ldc教学。

In JVM Specification I found term I don't understand: symbolic reference , and I have the following questions.在 JVM Specification 我发现 term I don't understand: symbolic reference ,我有以下问题。

  1. What does it mean?这是什么意思?

  2. Where is it used?它在哪里使用?

  3. In which cases does the ldc instruction load a symbolic reference? ldc指令在哪些情况下加载符号引用?
  4. Is there any code in Java corresponding to that action? Java 中是否有与该操作对应的代码?

It would be helpful if you would quote the exact piece of the documentation that's giving you trouble. 如果您引用给您带来麻烦的文档的确切内容,将很有帮助。 Since you haven't, I'm going to take a guess at what you might have quoted, from the doc for ldc : 既然您还没有,那么我将对ldc的文档中您可能引用的内容进行猜测

Otherwise, if the run-time constant pool entry is a symbolic reference to a class (§5.1), then the named class is resolved (§5.4.3.1) and a reference to the Class object representing that class, value, is pushed onto the operand stack. 否则,如果运行时常量池条目是对类的符号引用(第5.1节),则将解析命名的类(第5.4.3.3.1节),并将对表示该类值的Class对象的引用推送到操作数堆栈。

Otherwise, the run-time constant pool entry must be a symbolic reference to a method type or a method handle (§5.1). 否则,运行时常量池条目必须是对方法类型或方法句柄的符号引用(第5.1节)。 ... ...

This quote has a link to another section of the JVM spec (5.1), which describes the run-time constant pool: 此引号具有指向JVM规范(5.1)另一部分的链接,该部分描述了运行时常量池:

a run-time data structure that serves many of the purposes of the symbol table of a conventional programming language implementation 一种运行时数据结构,可满足常规编程语言实现的符号表的许多目的

What this means is that the run-time constant pool contains information about the pieces of a class in symbolic form: as text values. 这意味着运行时常量池以符号形式包含有关类片段的信息:作为文本值。

So, when ldc is given a "symbolic reference" to a class, it's given the index of a CONSTANT_Class_info structure within the constant pool. 因此,当给ldc一个类的“符号引用”时, ldc被给定了常量池中CONSTANT_Class_info结构的索引。 If you look at the definition of this structure, you'll see that it contains a reference to the name of the class, also held within the constant pool. 如果查看此结构的定义,将会看到它包含对类名的引用,该类名也保存在常量池中。

TL;DR: "symbolic references" are strings that can be used to retrieve the actual object. TL; DR: “符号引用”是可用于检索实际对象的字符串。


An example: 一个例子:

if (obj.getClass() == String.class) {
    // do something
}

Becomes the following bytecode: 变为以下字节码:

aload_1
invokevirtual   #21; //Method java/lang/Object.getClass:()Ljava/lang/Class;
ldc     #25; //class java/lang/String
if_acmpne       20

In this case, the ldc operation refers to a class that is stored symbolically. 在这种情况下, ldc操作引用的是符号存储的类。 When the JVM executes this opcode, it will use the symbolic reference to identify the actual class within the current classloader, and return a reference to the class instance. 当JVM执行此操作码时,它将使用符号引用来标识当前类加载器中的实际类,并返回对该类实例的引用。

To add to the other answer for parts 1&2 only of the question:要添加到问题的第 1 部分和第 2 部分的其他答案:

Currently, the JVM uses run-time data areas that can be divided into six areas: • The program counter (PC) register • Java Virtual Machine (JVM) stacks • Native method stacks • Heap Area • Method area • Run-Time Constant Pool目前,JVM 使用的运行时数据区可分为六个区域: • 程序计数器 (PC) 寄存器 • Java 虚拟机 (JVM) 堆栈 • 本机方法堆栈 • 堆区 • 方法区 • 运行时常量池

The PC register is used to store the address of the next instruction, which is the instruction code to be executed. PC寄存器用来存放下一条指令的地址,也就是要执行的指令代码。 The execution engine reads the next instruction and the JVM uses this to keep track of the executions of threads, because the CPU will constantly switch between them.执行引擎读取下一条指令,JVM 使用它来跟踪线程的执行,因为 CPU 会不断地在它们之间切换。

The stack frame has three parts: the Local Variable Array, the Operand Stack and the Frame Data.栈帧由三部分组成:局部变量数组、操作数栈和帧数据。

  1. The purpose of the Operand Stack is for any intermediate operations that may be required, such as addition or subtraction of numbers.操作数堆栈的目的是用于可能需要的任何中间操作,例如数字的加法或减法。 The operand stack acts as runtime workspace to perform the operation.操作数堆栈充当运行时工作区来执行操作。
  2. The Local Variable Array contains all parameters and local variables of the method.局部变量数组包含方法的所有参数和局部变量。
  3. Frame Data: contains all symbolic references (constant pool resolution) and normal method returns related to that particular method.帧数据:包含所有符号引用(常量池解析)和与该特定方法相关的正常方法返回。

Native Stacks are used when an implementation of the Java Virtual Machine is using conventional stacks, colloquially called "C stacks," to support native methods (methods written in a language other than the Java programming language).当 Java 虚拟机的实现使用常规堆栈(俗称“C 堆栈”)来支持本机方法(以 Java 编程语言以外的语言编写的方法)时,使用本机堆栈。

The heap is the run-time data area from which memory for all class instances and arrays is allocated.堆是运行时数据区域,所有 class 实例和 arrays 的 memory 从该区域中分配。

The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. Java 虚拟机具有在所有 Java 虚拟机线程之间共享的方法区域。 The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process.方法区类似于传统语言的编译代码的存储区,或者类似于操作系统进程中的“文本”段。 It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods used in class and interface initialization and in instance initialization (§2.9).它存储每个类的结构,例如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括 class 和接口初始化和实例初始化中使用的特殊方法(第 2.9 节)。

A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4)运行时常量池是 class 文件(第 4.4 节)中 constant_pool 表的按类或按接口运行时表示

So what does that mean in practical terms?那么这实际上意味着什么呢? My understanding is that it is an abstraction to reference classes without any side effects.我的理解是,它是引用类的抽象,没有任何副作用。

For example, what if you were using the Class object instead of the constant pool symbols for storing class structures at runtime and it didn't load properly?例如,如果您在运行时使用 Class object 而不是用于存储 class 结构的常量池符号并且它没有正确加载怎么办? I've seen a code base with multiple jars of the same name, type, and version all loaded from different areas of the code, because multiple teams worked on separate sections of a large code base and didn't bother to clean up the mess.我见过一个代码库,其中包含多个相同名称、类型和版本的 jars,它们都是从代码的不同区域加载的,因为多个团队在一个大型代码库的不同部分工作,并没有费心清理混乱. I also worked with tuples of strings as a means of constructing a unique location in a transportation program.我还使用字符串元组作为在运输程序中构建独特位置的一种方法。 It worked, but it seemed to be a clunky mechanism for handling the use case.它有效,但它似乎是处理用例的笨拙机制。 So my point is, the symbolic representations for classes and interfaces fill that need and create a standard procedure to reference classes during runtime, without side effects, to my knowledge.所以我的观点是,据我所知,类和接口的符号表示满足了这一需求,并创建了一个标准过程来在运行时引用类,而没有副作用。

To quoteBrian Goetz on this:引用Brian Goetz的话:

Activities such as bytecode generation have a frequent need to describe constants such as classes.诸如字节码生成之类的活动经常需要描述诸如类之类的常量。 However, a Class object is a poor description for an arbitrary class.但是,对于任意 class,Class object 描述不佳。 Producing a Class instance has many environmental dependencies and failure modes;生产一个 Class 实例有很多环境依赖和故障模式; loading may fail in because the desired class does not exist or may not be accessible to the requestor, the result of loading varies with class loading context, loading classes has side-effects, and sometimes may not be possible at all (such as when the classes being described do not yet exist or are otherwise not loadable, as in during compilation of those same classes, or during jlink-time transformation.) So, while the String class is a fine description for a Constant_String_info, the Class type is not a very good description for a Constant_Class_info.加载可能会失败,因为所需的 class 不存在或请求者可能无法访问,加载结果因 class 加载上下文而异,加载类有副作用,有时可能根本不可能(例如当所描述的类尚不存在或无法加载,例如在编译这些相同的类期间或在 jlink 时间转换期间。)因此,虽然字符串 class 是对 Constant_String_info 的良好描述,但 Class 类型不是对 Constant_Class_info 的很好描述。

A number of activities share the need to deal with classes, methods, and other entities in a purely nominal form.许多活动都需要以纯粹的名义形式处理类、方法和其他实体。 Bytecode parsing and generation libraries must describe classes and method handles in symbolic form.字节码解析和生成库必须以符号形式描述类和方法句柄。 Without an official mechanism, they must resort to ad-hoc mechanisms, whether descriptor types like ASM's Handle, or tuples of strings (method owner, method name, method descriptor), or ad-hoc (and error-prone) encodings of these into a single string.如果没有官方机制,他们必须求助于 ad-hoc 机制,无论是像 ASM 的句柄这样的描述符类型,还是字符串元组(方法所有者、方法名称、方法描述符),或者这些的 ad-hoc(和容易出错)编码到单个字符串。 Bootstraps for invokedynamic that operate by spinning bytecode (such as LambdaMetafactory) would prefer to work in a symbolic domain rather than with live classes and method handles.通过旋转字节码(例如 LambdaMetafactory)操作的 invokedynamic 引导程序更喜欢在符号域中工作,而不是使用实时类和方法句柄。 Compilers and offline transformers (such as jlink plugins) need to describe classes and members for classes that cannot be loaded into the running VM.编译器和离线转换器(例如 jlink 插件)需要为无法加载到正在运行的 VM 中的类描述类和成员。 Compiler plugins (such as annotation processors) similarly need to describe program elements in symbolic terms.编译器插件(例如注释处理器)同样需要用符号术语来描述程序元素。 They would all benefit from having a single, official way to describe such constants.他们都会受益于用一种单一的、官方的方式来描述这些常量。

The Java docs quoted and elaborated on were fromJava SE 12 .引用和阐述的 Java 文档来自Java SE 12

There are diagrams to illustrate this: the JVM Architecture from Dzone.有图表可以说明这一点: Dzone 的 JVM 架构。

Last of all is An Introduction to the Constant Pool in the JVM by Baeldung that illustrates a simple Hello World program with bytecode.最后是Baeldung 的 JVM 中的常量池简介,它用字节码说明了一个简单的 Hello World 程序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM