什么是Class常量池,和运行时常量池关系是什么?

1 个回答

  • 西蒙
    热爱漫无边际,生活自有分寸。
    ### **1. Class 常量池(Class Constant Pool)** **Class 常量池**是 **Class 文件中的资源仓库**,用于存储 **编译期生成的字面量(Literal)和符号引用(Symbolic References)**。 它是 **Java 字节码的一部分**,用于支持类加载和运行时解析。 #### **Class 常量池存储的内容** - **字面量(Literal)** - 基本类型常量(如 `int`、`float`) - 字符串常量(如 `"Hello"`) - **符号引用(Symbolic References)** - **类和接口的全限定名** - **字段名称和描述符** - **方法名称和描述符** - **接口方法的引用** #### **Class 常量池的特点** - **存储在 `.class` 文件中**,在编译时生成。 - **是方法区的一部分**,但不同 JDK 版本的存储方式不同。 - **在类加载时被 JVM 解析**,用于支持方法解析、动态绑定等。 ### **2. 运行时常量池(Runtime Constant Pool)** **运行时常量池**是 **JVM 方法区的一部分**,它在 **类加载时** 从 **Class 常量池** 解析并存储 **实际的常量值和引用**。 #### **运行时常量池的作用** - **存储 Class 常量池解析后的内容** - **支持动态常量** - **支持 `String.intern()`** - **可在运行时动态修改** #### **运行时常量池与 Class 常量池的关系** 1. **Class 常量池** → **运行时常量池** - 当类加载时,JVM **解析 `.class` 文件**,将 Class 常量池的数据加载到运行时常量池中。 2. **运行时常量池支持动态添加** - 运行时常量池不仅包含 `.class` 中的常量,还支持运行时动态添加,如 `String.intern()`。 ### **3. 运行时常量池存储位置的变化** | **JDK 版本** | **运行时常量池存储位置** | **特点** | |------------|-----------------|------------| | **JDK 1.6 及之前** | **永久代(PermGen)** | 容量有限,容易 OOM | | **JDK 1.7** | **常量池从永久代移到堆** | `String.intern()` 存在堆中 | | **JDK 1.8 及之后** | **常量池存放在 Metaspace** | 使用本地内存,避免 OOM | ### **4. 如何查看 Class 常量池** 可以使用 `javap -v` 命令反编译 `.class` 文件,查看 Class 常量池内容。 ```shell javap -v HelloWorld.class ``` 示例输出: ```plaintext Constant pool: #1 = Methodref #6.#15 // java/lang/Object."<init>":()V #2 = Class #16 // HelloWorld #3 = Utf8 HelloWorld #4 = Utf8 main #5 = Utf8 ([Ljava/lang/String;)V #6 = Class #17 // java/lang/Object #7 = Utf8 java/lang/Object #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 SourceFile #11 = Utf8 HelloWorld.java ``` - **`#1 = Methodref #6.#15`**:表示方法引用,指向 `Object.<init>()`。 - **`#3 = Utf8 HelloWorld`**:存储类名 `HelloWorld`。 - **`#6 = Class #17`**:表示 `java/lang/Object` 的符号引用。 ### **5. 运行时常量池的作用** #### **(1) 字符串常量池** ```java String s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2); // true ``` - `"hello"` 被存储在 **运行时常量池**,`s1` 和 `s2` 指向同一对象。 #### **(2) `String.intern()`** ```java String s1 = new String("hello").intern(); String s2 = "hello"; System.out.println(s1 == s2); // true ``` - `intern()` 方法会**检查运行时常量池**,如果已存在相同的字符串,则返回池中的引用。 ### **6. 总结** | **概念** | **存储位置** | **作用** | |---------|------------|------------| | **Class 常量池** | `.class` 文件 | 编译时存储字面量 & 符号引用 | | **运行时常量池** | 方法区(JDK 1.6 及之前为永久代,JDK 1.7+ 为堆或 Metaspace) | 运行时解析 Class 常量池,支持 `String.intern()` | - **Class 常量池是 Class 文件的一部分,存储编译期的常量** - **运行时常量池加载 Class 常量池,并允许动态添加** - **JDK 1.7 及之后,运行时常量池被移至堆或 Metaspace,避免 PermGen OOM**
    发布于 2025-03-16 01:57 •IP属地 西藏
    举报
    评论
    收藏