在 Java 应用程序的执行过程中,对象引用是由运行时使用还是在编译时被剥离?
我想我可以反编译类文件,看看它们是如何用作局部变量和成员变量的。
当您不需要时创建对象引用是浪费还是编译器会删除不需要的引用?
例如
最终字符串 abc = "abc"; 方法(ABC);
相对于:
方法(“ABC”);
在 Java 应用程序的执行过程中,对象引用是由运行时使用还是在编译时被剥离?
我想我可以反编译类文件,看看它们是如何用作局部变量和成员变量的。
当您不需要时创建对象引用是浪费还是编译器会删除不需要的引用?
例如
最终字符串 abc = "abc"; 方法(ABC);
相对于:
方法(“ABC”);
方法存储在对象数据区域中(如类定义所示),但块本地引用存储在 JVM 堆栈帧的特殊区域中。当帧从执行线程的帧堆栈中弹出时,所有块本地引用都将丢失,因为它们实际上并未存储在对象的数据结构中。
请注意,如果您不熟悉 JVM 堆栈帧,则会为每个方法的入口获取一个新的堆栈帧,并在从方法返回时从线程的堆栈中弹出。堆栈帧包含许多元素,包括指向当前指令(位于类的指令页中)的指针、指向“this”对象的指针,以及用于保存当前方法计算中的中间体的小堆栈。有时变量引用不需要存储,许多优化编译器随后会编译出代码以使用本地堆栈而不是“对象引用存储”,这意味着逆向代码将导致无法发现该人完全使用了一个变量。
“this”指针始终占据对象引用存储区的第一个条目,所有这些概念都是概念性的。实际实现只需要符合操作标准,不需要符合特定的内存布局。
在字节码级别,不会删除像这样“不必要的”引用;您可以在字节码中看到上述分配。但是 JIT(即 HotSpot)通常更智能,因此运行时影响基本上为零。
在您提到的特定情况下,您命名一个局部变量并将其称为“abc”这一事实本质上对您作为程序员来说是一种方便。无论您是这样做还是只是将其保留为未命名的参数,字节码基本上都会以相同的方式结束。
通常,您无需担心该级别的详细信息。您可以信任字节码编译器和 JIT 编译器来做明智的事情。如果您不得不担心到这种详细程度,那么几乎不可能编写任何中等复杂性的应用程序......
[PS 如果你有时间和兴趣,我也建议你反编译相应的类,作为一个教育练习。但是你会发现应该是相当令人放心的:编译器在做一般明智的事情,没有必要偏执。]