写点什么

字符串常量池 -String.intern 源码实现 3/3

作者:储诚益
  • 2025-01-28
    安徽
  • 本文字数:2686 字

    阅读完需:约 9 分钟

String.intern() 是 Java 中用于操作字符串常量池的关键方法。它的作用是将字符串对象添加到字符串常量池中(如果池中不存在相同内容的字符串),并返回池中的字符串引用。为了深入理解它的实现原理,我们需要从 Java 层到 JVM 层逐步分析其工作机制。

1. Java 层的 String.intern() 方法

在 Java 标准库中,String.intern() 是一个本地方法(native),其具体实现由 JVM 提供。它的作用是将当前字符串对象添加到字符串常量池中(如果池中不存在相同内容的字符串),并返回池中的字符串引用。方法定义如下:

public native String intern();
复制代码

2. JVM 层的 String.intern() 实现

当 Java 代码调用 String.intern() 时,JVM 会通过本地方法接口(JNI)调用 JVM 层的实现。

JNI 方法定义

JVM 需要在启动时注册 String.intern() 的本地方法实现。这个过程通常发生在 JVM 初始化阶段。

在 OpenJDK 源码中,String.intern() 的 JNI 方法定义位于 jvm.cpp 文件中:

// hotspot/src/share/vm/prims/jvm.cpp// JNI 方法入口宏,用于处理 JNI 调用时的环境设置和清理JNI_ENTRY(jstring, jvm_intern(JNIEnv* env, jstring str))  JVMWrapper("JVM_InternString");  // JVM 包装器,用于调试和日志记录  JvmtiVMObjectAllocEventCollector oam;  // 用于收集 JVMTI 对象分配事件
// 如果传入的字符串为 null,直接返回 null if (str == nullptr) return nullptr;
// 将 Java 层的 jstring 对象转换为 JVM 内部的 oop(普通对象指针) oop string = JNIHandles::resolve_non_null(str);
// 调用 StringTable::intern 方法,将字符串添加到字符串常量池中 oop result = StringTable::intern(string, CHECK_NULL);
// 将 JVM 内部的 oop 转换为 Java 层的 jstring 对象,并返回 return (jstring) JNIHandles::make_local(env, result);JNI_END // JNI 方法结束宏,用于清理 JNI 调用环境
复制代码
  • JNI_ENTRY 和 JNI_END:这是 JNI 方法的宏定义,用于处理 JNI 调用时的环境设置和清理。

  • jvm_intern:这是 String.intern() 的本地方法实现。

  • JNIHandles::resolve_non_null:将 Java 层的 jstring 对象转换为 JVM 内部的 oop(普通对象指针)。

  • StringTable::intern:调用 JVM 内部的 StringTable::intern() 方法,将字符串添加到字符串常量池中。

JNI 方法绑定

在 JVM 启动时,String.intern() 的本地方法实现会被绑定到 Java 层的 intern() 方法。这个过程是通过 JNIEnv::RegisterNatives 完成的。在 OpenJDK 源码中,String.intern() 的 JNI 方法绑定位于 SystemDictionary::initialize() 方法中:

// hotspot/src/share/vm/classfile/systemDictionary.cppvoid SystemDictionary::initialize(TRAPS) {  // 获取 Java 层的 String 类的 Klass 对象  Klass* stringKlass = SystemDictionary::String_klass();
// 获取当前线程的 JNI 环境 JNIEnv* env = JavaThread::current()->jni_environment();
// 定义需要注册的本地方法 JNINativeMethod methods[] = { { "intern", "()Ljava/lang/String;", (void*)&jvm_intern } // 注册 String.intern() 方法 };
// 将 Java 层的 intern() 方法与 JVM 层的 jvm_intern() 实现绑定 env->RegisterNatives(stringKlass, methods, 1);}
复制代码
  • JNINativeMethod:这是一个结构体,用于描述本地方法的名称、签名和实现。

  • RegisterNatives:将 Java 层的 intern() 方法与 JVM 层的 jvm_intern() 实现绑定

StringTable::intern() 实现

当 JNI 调用 jvm_intern() 时,JVM 会进一步调用 StringTable::intern() 方法,完成字符串常量池的操作。

// hotspot/src/share/vm/classfile/stringTable.cpp
// 将字符串添加到字符串常量池中(核心逻辑)oop StringTable::intern(Handle string_or_null, jchar* name, int len, uintx hash, TRAPS) { // 计算哈希桶的索引 int index = the_table()->hash_to_index(hash);
// 在哈希桶中查找是否已经存在相同内容的字符串 oop found_string = the_table()->lookup(index, name, len, hash);
// 如果找到匹配的字符串,直接返回池中的字符串引用 if (found_string != nullptr) { return found_string; }
// 如果未找到匹配的字符串,则将当前字符串添加到常量池中 return the_table()->basic_add(index, string_or_null, name, len, hash, THREAD);}
复制代码


  • java_lang_String::as_unicode_string:从 oop 对象中提取字符串内容。

  • java_lang_String::length:获取字符串的长度。

  • StringTable::intern:调用内部的 intern 方法,完成字符串常量池的操作。

详细内容请阅读https://xie.infoq.cn/article/be2da49fce15ad02f936c28e9

3. 实现原理总结

Java 代码调用 String.intern() 方法,由于 intern() 是一个 native 方法,调用会通过 JNI 传递到 JVM 层。JNI 层的 jvm_intern() 方法是 String.intern() 的具体实现。它负责将 Java 层的 jstring 对象转换为 JVM 内部的 oop(普通对象指针),调用 StringTable::intern() 方法,完成字符串常量池的操作。StringTable::intern() 方法是 JVM 内部实现字符串常量池的核心方法。它的主要逻辑包括:计算哈希值查找字符串常量池插入字符串

+-------------------+       +-------------------+       +-------------------+|   Java 层         |       |   JNI 层          |       |   JVM 层          ||                   |       |                   |       |                   ||  String.intern()  | ----> |  jvm_intern()     | ----> |  StringTable::intern()|                   |       |                   |       |                   |+-------------------+       +-------------------+       +-------------------+        |                           |                           |        |                           |                           |        v                           v                           v+-------------------+       +-------------------+       +-------------------+|  Java 代码调用    |       |  JNI 方法实现     |       |  字符串常量池操作  ||  String.intern()  |       |  jvm_intern()     |       |  StringTable::intern()|                   |       |                   |       |                   |+-------------------+       +-------------------+       +-------------------+
复制代码


发布于: 刚刚阅读数: 5
用户头像

储诚益

关注

还未添加个人签名 2017-12-19 加入

还未添加个人简介

评论

发布
暂无评论
字符串常量池 -String.intern 源码实现 3/3_string pool_储诚益_InfoQ写作社区