String类内存浅析
Posted liqbk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了String类内存浅析相关的知识,希望对你有一定的参考价值。
String类中的常量池分析
Java中的字符串常量池
Java中字符串对象创建有两种形式:
1 字面直接赋值形式,如 String str = "liq";
2 通过 new 构造对象的方法 String str = new String("liq");
上述两种创建方式在性能和内存上存在一定的差异.
原因就是:JVM为了减少字符串对象的重复创建,维护了一个特殊的内存,这段内存就是字符串常量池
工作原理分析
当使用第一种直接赋值的方式创建字符串对象时,JVM首先对这个字面量进行检查,如果字符串常量池中存在相同的内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个对象的引用放入字符串常量池,并返回该引用.
内存模型如下:
举例说明
第一种方式:直接赋值
String s1 = "liq";
//JVM检测这个字面量,这里我们认为没有内容为`liq`的对象存在。JVM通过字符串常量池查找不到内容为`liq`的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量s1。
String s2 = "liq";
//同样JVM还是要检测这个字面量,JVM通过查找字符串常量池,发现内容为”liq”字符串对象存在,于是将已经存在的字符串对象的引用返回给变量s2。注意这里不会重新创建新的字符串对象。所以用的是同一个地址.结果为true.
System.out.println(s1==s2);
测试结果:
true
第二种方式:使用new创建
String s1 = "liq";
String s3 = new String("liq");
//当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。所以即使内容相同,占用的也不是同一个地址.当比较地址的时候一定不同.但是比较内同的时候就是相同的啦
System.out.println(s1==s3);
System.out.println(s1.equals(s3));
测试结果
false
true
对于使用new创建的字符串对象:
如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。
调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。
举例intern
String s1 = "liq";
String s3 = new String("liq");
String s4 = s3.intern();
//这里使用intern方法,将通过new创建字符串的对象的引用添加到常量池种.调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。
System.out.println(s1==s4);//true 原来的常量池中存在
面试题:
String s = new String(“xyz”); 产生几个对象?
一个或两个。如果常量池中原来没有 ”xyz”, 就是两个。如果原来的常量池中存在“xyz”时,就是一个。对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。
java中String new和直接赋值的区别
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
以上是关于String类内存浅析的主要内容,如果未能解决你的问题,请参考以下文章