展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > 如何使用Java String的intern()方法?

如何使用Java String的intern()方法?

Internet Download Manager
Internet Download Manager

是Windows平台老牌而功能强大的下载工具,备受众多国外用户的青睐。

¥59
2026-08-22
系统应用 系统工具 Internet Download Manager 本月促销
立即下载

常量池简介在JAVA语言中有8种基本类型和一种比较特殊的类型String。这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池(在方法区)的概念。常量池就类似一个JAVA系统级别提供的缓存。8种基本类型的常量池都是系统协调的,String类型的常量池比较特殊。String的常量池的主要使用方法有两种:直接使用双引号声明出来的String对象会直接存储在常量池中。如果不是用双引号声明的String对象,可以使用String提供的intern方法将其放到常量池。intern方法简介(JDK7

本文目录

      常量池简介

      在 JAVA 语言中有8种基本类型和一种比较特殊的类型String。这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池(在方法区)的概念。常量池就类似一个JAVA系统级别提供的缓存。8种基本类型的常量池都是系统协调的,String类型的常量池比较特殊。

      String的常量池的主要使用方法有两种:

      直接使用双引号声明出来的String对象会直接存储在常量池中。

      如果不是用双引号声明的String对象,可以使用String提供的intern方法将其放到常量池。

      intern方法简介(JDK7)

      原型:public native String intern();

      说明:

      从字符串常量池中查询当前字符串是否存在(通过equals判断)。

      • 如果存在,返回常量池中的字符串引用。

      • 如果不存在,把这个String对象引用存到常量池,然后返回这个String对象的引用。

      返回值:都是返回String变量对应的字符串常量池的引用。

      示例

      package com.example;
       
      public class Demo {
          public static void main(String argv[]) {
              String s = "test";
              System.out.println(s == s.intern());
          }
      }

      JDK6及之前:输出false

      JDK7及之后:输出true

      原理(JDK6与JDK7)

      常量池里的字符串的由来

      JDK6及以前调用String.intern()

      • 若常量池中有,则返回常量池中这个字符串的引用

      • 若常量池中没有,则拷贝一份对象,放到常量池(永久代)中;返回值是常量池(永久代)中对应字符串实例的引用。

      JDK7及以后调用String.intern()

      • 若常量池中有,则返回常量池中这个字符串的引用

      • 若常量池中没有,则拷贝一份引用,放到常量池(堆)中;(JDK1.7将String常量池从Perm区移动到了Java Heap区)

      例程测试

      例程1: 

      package org.example.a;
       
      public class Demo {
          public static void main(String argv[]) {
              String s1 = new String("1");
              s1.intern();
              String s2 = "1";
              System.out.println(s1 == s2);
       
              String s3 = new String("1") + new String("1");
              s3.intern();
              String s4 = "11";
              System.out.println(s3 == s4);
          }
      }

      结果

      jdk6:false false
      jdk7:false true
      jdk8:false true

      例程2: 

      package org.example.a;
       
      public class Demo {
          public static void main(String argv[]) {
              String s1 = new String("1");
              s1.intern();
              String s2 = "1";
              System.out.println(s1 == s2);
       
              String s3 = new String("1") + new String("1");
              String s4 = "11";
              s3.intern();
              System.out.println(s3 == s4);
          }
      }

      上述代码第二部分有个对调。

      结果

      jdk6:false false
      jdk7:false false
      jdk8:false false

      例程分析

      下边图中:绿色线条代表 String 对象的内容指向。 红色线条代表地址指向。

      jdk1.6

      例程1与例程2的分析

      如何使用Java String的intern()方法?

      如上图所示。首先说一下 jdk6中的情况,在 jdk6中上述的所有打印都是 false 的,因为 jdk6中的常量池是放在 Perm 区中的,Perm区和正常的 JAVA Heap 区域是完全分开的。上面说过如果是使用引号声明的字符串都是会直接在字符串常量池中生成,而 new出来的 String 对象是放在 JAVA Heap 区域。所以拿一个 JAVA Heap 区域的对象地址和字符串常量池的对象地址进行比较肯定是不相同的,即使调用String.intern方法也是没有任何关系的。

      jdk1.7

      在 Jdk6 以及以前的版本中,字符串的常量池是放在堆的Perm区的,Perm区是一个类静态的区域,主要存储一些加载类的信息,常量池,方法片段等内容,默认大小只有4m,一旦常量池中大量使用 intern 会产生java.lang.OutOfMemoryError:PermGen space错误的。在 jdk7 的版本中,字符串常量池已经从Perm区移到正常的Java Heap区域了。为什么要移动,Perm 区域太小是一个主要原因,当然据消息称jdk8已经直接取消了Perm区域,而新建立了一个元区域。应该是jdk开发者认为Perm区域已经不适合现在 JAVA的发展了。字符串常量池移动到JAVA Heap区域,现在解释为什么会有上述的打印结果。

      例程1的分析

      如何使用Java String的intern()方法?

      1.String s1 = new String("1"); 

      分析:这行代码生成了2个对象(常量池中的“1” 和 JavaHeap 中的字符串对象)。s.intern(); 这一句是 s1 对象去常量池中寻找后发现 “1” 已经在常量池里了。

      此时s1指向的是Java Heap中的字符串对象。

      2.String s2 = "1"; 

      分析:这行代码生成一个 s2的引用指向常量池中的“1”对象。 结果就是 s1 和 s2 的引用地址不同。

      3.String s3 = new String("1") + new String("1");

      分析:这行代码生成了2个对象(字符串常量池中的“1” 和 Java Heap中的 s3 引用指向的对象“11”(中间还有2个匿名的new String("1")我们不讨论它)。
      此时s3 是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是没有 “11”对象的。

      4.s3.intern();

      分析:这行代码将 s3中的"11"字符串放入String 常量池中,因为此时常量池中不存在"11"字符串,因此常规做法是跟 jdk6 图中表示的那样,在常量池中生成一个"11"的对象,关键点是 jdk7 中常量池不在Perm区域,而是在堆中了。常量池中不需再存储一份对象了,可以直接存储堆中的引用。这份引用指向s3引用的对象。 也就是说引用地址是相同的。

      此时,s3是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是有 “11”对象,它保存的就是s3引用地址。

      5.String s4 = "11"; 

      这行代码”11″是显式声明的,因此会直接去常量池中创建,创建时发现已经有这个对象了。

      此时:s4 == 常量池的“11”对象引用 == s3引用对象的引用

      例程2的分析

      如何使用Java String的intern()方法?

      String s1 = new String("1");

      s1.intern();

      String s2 = "1";

      分析:s1.intern();,这一句往后放也不会有什么影响了,因为对象池中在执行第一句代码String s = new String("1");的时候已经生成“1”对象了。下边的s2声明都是直接从常量池中取地址引用的。 s1 和 s2 的引用地址是不会相等的。

      String s3 = new String("1") + new String("1");

      分析:这行代码生成了2个对象(字符串常量池中的“1” 和 Java Heap中的 s3 引用指向的对象“11”(中间还有2个匿名的new String("1")我们不讨论它)。

      此时s3 是Java Heap中的字符串对象的引用,对象内容是”11″,此时常量池中是没有 “11”对象的。

      String s4 = "11";

      分析:声明 s4 的时候常量池中是不存在“11”对象的,执行完后,s4是常量池里“11“对象的引用。

      s3.intern(); 

      分析:此时常量池中“11”对象已经存在了,不会有任何操作,s3仍然是堆中String对象的引用。因此 s3 != s4

      应用实例

      package org.example.a;
       
      import java.util.Random;
       
      public class Demo {
          static final  int MAX = 1000 * 10000;
          static final String[] arr = new String[MAX];
          public static void main(String argv[]) {
              Integer[] DB_DATA = new Integer[10];
              Random random = new Random(10 * 10000);
              for(int i = 0; i < DB_DATA.length; i++){
                  DB_DATA[i] = random.nextInt();
              }
       
              long t = System.currentTimeMillis();
              for(int i = 0; i < MAX; i++){
                  //arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length]));
                  arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])).intern();
              }
       
              System.out.println((System.currentTimeMillis() -t) + "ms");
              System.gc();
          }
      }

      上述代码是一个演示代码,其中有两条语句不一样,一条是使用 intern,一条是未使用 intern。

      运行的参数是:-Xmx2g -Xms2g -Xmn1500M

      不用intern

      2160ms

      如何使用Java String的intern()方法?

      使用intern

      826ms

      如何使用Java String的intern()方法?

      通过上述结果,我们发现不使用 intern 的代码生成了1000w 个字符串,占用了大约640m 空间。 使用了 intern 的代码生成了1345个字符串,占用总空间 133k 左右。其实通过观察程序中只是用到了10个字符串,所以准确计算后应该是正好相差100w 倍。虽然例子有些极端,但确实能准确反应出 intern 使用后产生的巨大空间节省。

      细心的同学会发现使用了 intern 方法后时间上有了一些增长。这是因为程序中每次都是用了 new String 后, 然后又进行 intern 操作的耗时时间,这一点如果在内存空间充足的情况下确实是无法避免的,但我们平时使用时,内存空间肯定不是无限大的,不使用 intern占用空间导致 jvm 垃圾回收的时间是要远远大于这点时间的。 毕竟这里使用了1000w次intern 才多出来1秒钟多的时间。

      本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
      作者最新文章
      编程开发 Java
      相关文章 更多
      精品专题 更多
      装机必备

      正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

      Windows

      正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

      PDF教程

      正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

      macOS软件

      正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

      IOS软件

      正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

      AI

      正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

      Mac软件 更多
      讯飞智作 网页版
      讯飞智作 网页版

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      Aperty macOS版
      Aperty macOS版

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      立刻MV 网页版
      立刻MV 网页版

      立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

      蛙蛙写作 网页版
      蛙蛙写作 网页版

      蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

      超级简历WonderCV 网页版
      超级简历WonderCV 网页版

      超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

      音述AI 网页版
      音述AI 网页版

      音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

      AionClaw macOS版
      AionClaw macOS版

      AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

      Loomy macOS版
      Loomy macOS版

      Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

      AirBuddy 3 macOS版
      AirBuddy 3 macOS版

      AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

      AirServer macOS版
      AirServer macOS版

      AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

      AnyDesk macOS版
      AnyDesk macOS版

      AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

      WINDOWS 更多
      讯飞智作 网页版
      讯飞智作 网页版

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      PixTV 网页版
      PixTV 网页版

      PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

      讯飞绘文 网页版
      讯飞绘文 网页版

      讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

      Maya(Autodesk Maya) Windows版
      Maya(Autodesk Maya) Windows版

      Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

      Aperty Windows版
      Aperty Windows版

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      立刻MV 网页版
      立刻MV 网页版

      立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

      蛙蛙写作 网页版
      蛙蛙写作 网页版

      蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

      超级简历WonderCV 网页版
      超级简历WonderCV 网页版

      超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

      音述AI 网页版
      音述AI 网页版

      音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

      AionClaw Windows版
      AionClaw Windows版

      AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

      Loomy Windows版
      Loomy Windows版

      Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

      即将离开本站
      您即将前往第三方网站,请确认是否继续?