专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java 深入解析常量池与装拆箱机制

temp10 2024-10-07 15:38:18 java教程 10 ℃ 0 评论

1.常量池

1.1概念

常量池是 Java 虚拟机 (JVM) 中一个特殊的内存区域,用于存储编译期间生成的各种字面量和符号引用。它可以分为两种:

Java 深入解析常量池与装拆箱机制

  • 编译时常量池: 存在于 .class 文件中,包含了类名、方法名、字段名等信息。
====编译时常量池存在于 .class 文件中,使用 constant_pool 表结构存储。=====
// .class 文件结构
constant_pool {
    u2 constant_pool_count;
    cp_info constant_pool[constant_pool_count - 1];
}

// 常量池信息结构
cp_info {
    u1 tag;
    u1 info[];
}

// 常量池信息类型
CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}
CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}
// ... 其他类型 ...

=========   示例   ==========
  // Test.java
public class Test {
    public static void main(String[] args) {
        System.out.println("hello");
    }
}
===== Test.class 文件中的常量池内容 =========
  Constant pool:
   #1 = Methodref          #4.#11         // java/lang/System.out.println:(Ljava/lang/String;)V
   #2 = Class              #12            // Test
   #3 = Utf8               main
   #4 = Class              #13            // java/lang/System
   #5 = Utf8               out
   #6 = Class              #14            // java/io/PrintStream
   #7 = Utf8               println:(Ljava/lang/String;)V
   #8 = Utf8               (Ljava/lang/String;)V
   #9 = Utf8               String
   #10 = Utf8               args
   #11 = NameAndType        #7:#8         // println:(Ljava/lang/String;)V
   #12 = Utf8               Test
   #13 = Utf8               java/lang/System
   #14 = Utf8               java/io/PrintStream
   #15 = Utf8               hello
   #16 = String             #15            // hello
   

#1 是一个方法引用,指向 java.lang.System.out.println(String) 方法。
#15 是一个 Utf8 类型常量,存储字符串 "hello"。
#16 是一个 String 类型常量,引用了 #15 中存储的 "hello" 字符串。
  • 运行时常量池: 存在于 JVM 的方法区中,包含了编译时常量池中的内容,以及运行时生成的常量。
String str1 = "hello";
String str2 = new String("hello");
String str3 = str1 + " world";

str1 的 "hello" 会被存储在 String 常量池中。
str2 的 "hello" 会在堆中创建一个新的 String 对象,不会被存储在 String 常量池中。
str3 的 "hello world" 会在堆中创建一个新的 String 对象,并存储在 String 常量池中。

注意:
String 常量池是运行时常量池的一部分,但它与其他类型常量的存储方式不同。
String 常量池中的对象是不可变的,即使使用 StringBuilder 或 StringBuffer 修改字符串,
也会创建一个新的 String 对象。

1.2常量池存储内容

  • 字面量: 包括字符串字面量、基本类型常量 (如 1、2.0、true 等)。
  • 符号引用: 指向类、方法、字段的引用,在类加载的时候会被解析为直接引用。

1.3常量池的作用

  • 提高代码效率: 重复使用常量池中的内容,避免重复创建对象,节省内存空间。
  • 支持动态加载: 运行时可以动态生成新的常量,并将其加入到常量池中。

1.4String常量池

String 常量池是运行时常量池的一个重要部分。当使用字符串字面量创建 String 对象时,JVM 会先在 String 常量池中查找是否存在相同的字符串对象。如果存在,则直接返回该对象;如果不存在,则创建一个新的 String 对象并将其加入 String 常量池。

装拆箱机制

2.1概念

Java 中的基本数据类型是值类型,而对象是引用类型。装箱是指将基本数据类型转换为对应的包装类对象,而拆箱是指将包装类对象转换为对应的基本数据类型。

2.2装箱

  • 使用包装类的构造函数: Integer i = new Integer(10);
  • 使用包装类的 valueOf() 方法: Integer i = Integer.valueOf(10);

2.3拆箱

  • 使用包装类的 xxxValue() 方法: int i = Integer.intValue();
  • 自动拆箱: 在需要基本数据类型的地方,会自动调用包装类的 xxxValue() 方法进行拆箱。

2.4装拆箱的原理

Java 编译器会将装箱和拆箱操作转换为相应的代码,例如:

  • 装箱: Integer i = new Integer(10); 会被转换为 Integer i = Integer.valueOf(10);
  • 拆箱: int i = Integer.intValue(); 会被转换为 int i = i.intValue();

2.5装拆箱的应用场景

  • 自动装拆箱: Java 中提供了自动装拆箱机制,方便了开发人员使用。
  • 泛型: 泛型中只能使用引用类型,所以需要将基本数据类型转换为包装类对象。
  • 集合: 集合只能存储对象,所以需要将基本数据类型转换为包装类对象。

2.6装拆箱的性能问题

装拆箱操作会带来一定的性能损耗,因为需要创建和销毁对象。在需要频繁进行装拆箱操作的场景中,应该尽量避免使用自动装拆箱机制,可以使用基本数据类型来提高效率。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表