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相等的字符串,在常量池中永远只有一份,在堆中有多份。

猜你喜欢

转载自www.cnblogs.com/liqbk/p/12905381.html