JVM详解(二)-- 第2章 类加载器子系统 (4)

常量池:常量池指的是字节码文件中的Constant pool部分。它是静态的,当编译生成字节码文件直接就不变了。常量池中包括各种字面量和对类型、域和方法的符号引用。几种在常量池内存储的数据类型包括:数量值、字符串值、类引用、字段引用、方法引用。

由此我们可以看出,上面我们给出的常量池中都属于“符号引用”(符号引用本身就是一种字面量)或字面量。我们不禁要问了了,那直接引用在哪呢?
我找到了《深入理解Java虚拟机》中的一句话:

对同一个符号引用进行多次解析请求是很常见的事情,除invokedynamic指令外,虚拟机实现可以对第一次解析的结果进行缓存(在运行时常量池中记录直接引用,并把常量标识为已解析状态)从而避免解析动作重复进行。

关键是括号中话给了启发,说明直接引用是放在运行时常量池中的,接下来我们看看运行时常量池的一些定义或特性。

运行时常量池是方法区的一部分。常量池用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。而加载类和接口到虚拟机后,就会创建对应的运行时常量池。
运行时常量池与常量池的不同点在于:
1. 运行时常量池中包括了编译期就已经明确的数值字面量,也包括在运行期解析后才能获得的方法或字段引用。但,请注意,此时的方法或字段引用已经不再是常量池中的“符号引用”,而是“直接引用”。
2. 运行时常量池具备“动态性”。

至此,关于“符号引用”和“直接引用”的解释就差不多了。最后我再多说一句,再分析的时候,我一直在疑惑“直接引用”到底是什么,我能不能像看到常量池中的内容一样看到“直接引用”。实际上,我们并不能拿到这样一个文件,里面整齐地写了直接引用的具体内容,因为直接引用不是所谓的“字面量”。但我们可以回到“直接引用”的最初定义:直接引用可以是指向目标的指针、相对偏移量或是能间接定位到目标的句柄,可以想象一下在运行时,在内存中存放的直接引用大概是什么内容。

六、其它

JVM 中两个Class对象是否为同一个类的必要条件

类的完整类名必须一致,包括包名。

加载这个类的ClassLoader(指ClassLoader实例对象)必须相同。
对类加载器的引用
JVM 必须知道一个类型是由启动类加载器加载的还是由用户类加载器加载的,如果一个类型是由用户类加载器加载的,那么 JVM 会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中,当解析一个类型到另一个类型的引用的时候, JVM 需要保证这两个类型的类加载器是相同的。

类的主动使用和被动使用
主动使用和被动使用的区别是,主动使用会导致类的初始化。
主动使用有以下七种情况:

创建类的实例。

访问某个类或接口的静态变量,或者对该静态变量赋值。

调用类的静态方法。

反射(比如:Class.forName("com,atguigu.Test"))。

初始化一个类的子类。

Java虚拟机启动时被标明为启动的类。

JDK 7开始提供的动态语言支持:java.lang.invoke.MethodHandle 实例的解析结果 REF_getStatic、REF_putStatic、 REF_invokeStatic句柄对应的类没有初始化则初始化。

参考文献:
https://blog.csdn.net/u011069294/article/details/107489721
https://www.cnblogs.com/cleverziv/p/13751488.html

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxdsx.html