对intern方法的学习来源于之前偶然看到的一篇博客:【请别再拿“String s = new String("xyz");创建了多少个String实例”来面试了吧】

博客地址:https://www.iteye.com/topic/774673

这篇博客写的很好,从各方面详细的讲解了Java底层的一些东西,不搞底层的看着可能会觉得很涩,很难懂,有兴趣的可以看看,当然本篇重点不在这边,而是对intern方法的使用方面的解析

在JDK1.6版本及以前,字符串常量池是存放在永久代中的,当使用intern方法的时候,会先查询字符串常量池中是否存在当前的字符串,如果不存在的话,就会将当前的字符串复制到字符串常量池中,并返回字符串常量池的引用。

JDK1.7以后,字符串常量池是存放在堆中的,当使用intern方法的时候,也会先查询字符串常量池中是否存在当前的字符串,如果不存在,再从堆中查询,然后存储并返回相关引用。如果都不存在的话,就会将当前的字符串复制到字符串常量池中,并返回字符串常量池的引用。

借用美团技术团队《深入解析String#intern》一文中两段代码与相关图片来进行解释:

第一段代码:

String s = new String("1");
s.intern();
String s2 = "1";
System.out.println(s == s2);String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
System.out.println(s3 == s4);

JDK1.6版本的运行结果为false false

解析:

String s = new String("1"),在字符串常量池中创建了“1”对象,在堆中创建了s对象。

s.intern(),因为字符串常量池已经有了“1”对象,所以可以跳过。

String s2 = "1",由于字符串常量池中已经存在“1”对象,所以s2直接指向字符串常量池中的“1”对象。

所以,s是堆中对象的引用,而s2指向的是字符串常量池,结果为false。

String s3 = new String("1") + new String("1"),在堆中创建了“1”对象,在字符串常量池中创建了s3对象。

s3.intern(),是直接将“11”复制到字符串常量池中。

String s4 = "11",指向了字符串常量池中的“11”。

所以,s3是堆中的引用,而s4指向的是字符串常量池,结果为false。

JDK1.7版本的结果为false true

解析:

s和s2的结果为false的原因同上。

而s3.intern(),返回的是堆中的引用,所以s4指向的其实也是堆中的引用,所以结果为true。

第二段代码:

String s = new String("1");
String s2 = "1";
s.intern();
System.out.println(s == s2);String s3 = new String("1") + new String("1");
String s4 = "11";
s3.intern();
System.out.println(s3 == s4);

这里将s2、s4对象的创建和intern方法的使用交换了一下顺序。

JDK1.6版本的运行结果为false false

解析:

上半段代码先在堆中创建了s对象,在字符串常量池创建了“1”对象,s2指向字符串常量池的“1”,这里的intern也就没有了实际的意义。所以一个指向堆中的引用,一个指向字符串常量池,false。

下半段代码是先在堆中创建了s3对象,在字符串常量池创建了“1”对象,又在字符串常量池中创建了“11”对象,所以,s3指向堆中的引用,s4指向字符串常量池,false。

JDK1.7版本的运行结果同样为false false

原理和1.6版本的解析基本一致,都是false,不是true,是因为上面的为true的是intern先执行,会存储堆中的引用,而这里是先执行的是String s4 = "11",在查询之前就重新创建了一个“11”对象,所以s3和s4指向的不是同一个,执行结果为false。

第三段代码:

static final int MAX = 1000 * 10000;
static final String[] arr = new String[MAX];public static void main(String[] args) throws Exception {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的结果为2044ms,不适用intern的结果为5016ms

总结一下:intern方法返回的是字符串对象的规范化表示形式,初衷就是为了让string对象能够被重复的使用,以此来节省内存的损耗。更深层次的对intern的解析可以参照:

美团技术团队《深入解析String#intern》 https://tech.meituan.com/in_depth_understanding_string_intern.html

Java—String类的intern方法的学习相关推荐

  1. Java String类的intern()方法

    该方法的作用是把字符串加载到常量池中(jdk1.6常量池位于方法区,jdk1.7以后常量池位于堆) 在jdk1.6中,该方法把字符串的值复制到常量区,然后返回常量区里这个字符串的值: 在jdk1.7里 ...

  2. Java String类的split方法简介

    Java String类的split方法简介 String的split()方法用于按传入的字符或字符串对String进行拆分,返回拆分之后的数组. 1.一般用法 用一般的字符,例如 @ 或 , 等符号 ...

  3. 关于Java中String类的intern()方法

    首先intern()方法的定义:当调用这个方法的时候,如果字符串常量池中有这个对象,就把常量池中的这个对象返回,没有就把当前对象加入到常量池并且返回当前对象的引用: jdk1.6之前:将对象存入常量池 ...

  4. Java技术——你真的了解String类的intern()方法吗

    0.引言 什么都先不说,先看下面这个引入的例子: [java] view plain copy String str1 = new String("SEU")+ new Strin ...

  5. Java技术——你真的了解String类的intern()方法吗,快点来学吧

    static final int MAX = 100000; static final String[] arr = new String[MAX]; public static void main( ...

  6. JAVA中String类的intern()方法的作用

    2019独角兽企业重金招聘Python工程师标准>>> 一般我们变成很少使用到 intern这个方法,今天我就来解释一下这个方法是干什么的,做什么用的 首先请大家看一个例子: [ja ...

  7. JDK1.8中String类的intern()方法学习

    jdk1.8字符串常量池是位于堆中: 在jdk1.8中使用如下指令时会同时在堆中和常量池(前提是常量池中还没有该对象)中创建字符串对象,但是s是指向堆中. String s = new String( ...

  8. String类的intern()方法详解

    0.引言 什么都先不说,先看下面这个引入的例子: [java] view plaincopy String str1 = new String("SEU")+ new String ...

  9. java String类常用的方法

    package Day0310.Demo02;public class StringTest02 {public static void main(String[] args) {System.out ...

最新文章

  1. 2008_12_24_星期三
  2. JAVA集合泛型,类型擦除,类型通配符上限之类的知识点
  3. 【问题记录】raise IndexError(‘index {} is out of range‘.format(idx)) index 0 is out of range
  4. C语言实现最大堆max_heap(附完整源码)
  5. python拾遗(二)
  6. Bad Request (Invalid Hostname)解决方法
  7. BlockChain: 区块链入门课程 -- 区块链适用于移动性 分享和收费案例
  8. Install And Configure ColdFusion MX 6.1 on Windows
  9. Netty源码解读(一)概述
  10. POJ 3378 树状数组+DP+离散化+高精度
  11. LintCode—删除链表中倒数第n个节点(174)
  12. 15投影矩阵与Moore-Penrose逆(1)
  13. 图书馆管理系统前景与范围文档
  14. AspNetPager常用属性及用法 / URLRewrite伪静态与AspNetPager分页控件的结合
  15. 计算View中的子View在View的superview中的坐标
  16. (三)Detecting Spacecraft Anomalies Using LSTMs and Nonparametric Dynamic Thresholding
  17. php聚合话费充值怎么接,求充值话费接口
  18. 【2004-3】【平分核桃】
  19. 给 Java 程序猿们推荐一些值得一看的好书
  20. 算法5:线性DP与区间DP

热门文章

  1. protege 简介
  2. 5G时代IDC数据中心经历变革,分布式云存储服务器将独占鳌头
  3. [数学]二维对数正态分布的概率分布,期望,方差和相关系数
  4. 代价函数/梯度下降法
  5. 微信公众号订阅号留言点赞采集抓取爬虫
  6. ESP32串口通信 双机串口通信
  7. matlab 群延迟,实现最小相位群延迟的音节切分算法的一些问题
  8. Quartz执行逻辑(三)QRTZ_FIRED_TRIGGERS表的作用
  9. QEMU 模拟启动 openEuler 的树莓派镜像
  10. 民办二本学计算机,2020湖南最垃圾的民办大学-湖南最差的民办二本