Java—String类的intern方法的学习
对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方法的学习相关推荐
- Java String类的intern()方法
该方法的作用是把字符串加载到常量池中(jdk1.6常量池位于方法区,jdk1.7以后常量池位于堆) 在jdk1.6中,该方法把字符串的值复制到常量区,然后返回常量区里这个字符串的值: 在jdk1.7里 ...
- Java String类的split方法简介
Java String类的split方法简介 String的split()方法用于按传入的字符或字符串对String进行拆分,返回拆分之后的数组. 1.一般用法 用一般的字符,例如 @ 或 , 等符号 ...
- 关于Java中String类的intern()方法
首先intern()方法的定义:当调用这个方法的时候,如果字符串常量池中有这个对象,就把常量池中的这个对象返回,没有就把当前对象加入到常量池并且返回当前对象的引用: jdk1.6之前:将对象存入常量池 ...
- Java技术——你真的了解String类的intern()方法吗
0.引言 什么都先不说,先看下面这个引入的例子: [java] view plain copy String str1 = new String("SEU")+ new Strin ...
- Java技术——你真的了解String类的intern()方法吗,快点来学吧
static final int MAX = 100000; static final String[] arr = new String[MAX]; public static void main( ...
- JAVA中String类的intern()方法的作用
2019独角兽企业重金招聘Python工程师标准>>> 一般我们变成很少使用到 intern这个方法,今天我就来解释一下这个方法是干什么的,做什么用的 首先请大家看一个例子: [ja ...
- JDK1.8中String类的intern()方法学习
jdk1.8字符串常量池是位于堆中: 在jdk1.8中使用如下指令时会同时在堆中和常量池(前提是常量池中还没有该对象)中创建字符串对象,但是s是指向堆中. String s = new String( ...
- String类的intern()方法详解
0.引言 什么都先不说,先看下面这个引入的例子: [java] view plaincopy String str1 = new String("SEU")+ new String ...
- java String类常用的方法
package Day0310.Demo02;public class StringTest02 {public static void main(String[] args) {System.out ...
最新文章
- 2008_12_24_星期三
- JAVA集合泛型,类型擦除,类型通配符上限之类的知识点
- 【问题记录】raise IndexError(‘index {} is out of range‘.format(idx)) index 0 is out of range
- C语言实现最大堆max_heap(附完整源码)
- python拾遗(二)
- Bad Request (Invalid Hostname)解决方法
- BlockChain: 区块链入门课程 -- 区块链适用于移动性 分享和收费案例
- Install And Configure ColdFusion MX 6.1 on Windows
- Netty源码解读(一)概述
- POJ 3378 树状数组+DP+离散化+高精度
- LintCode—删除链表中倒数第n个节点(174)
- 15投影矩阵与Moore-Penrose逆(1)
- 图书馆管理系统前景与范围文档
- AspNetPager常用属性及用法 / URLRewrite伪静态与AspNetPager分页控件的结合
- 计算View中的子View在View的superview中的坐标
- (三)Detecting Spacecraft Anomalies Using LSTMs and Nonparametric Dynamic Thresholding
- php聚合话费充值怎么接,求充值话费接口
- 【2004-3】【平分核桃】
- 给 Java 程序猿们推荐一些值得一看的好书
- 算法5:线性DP与区间DP