Java字符串常量池及字符串判等解析

一、理解“==”的含义

“==”常用于两个对象的判等操作,在Java中,“==”主要有以下两种用法:

1、基础数据类型:比较的是他们的值是否相等,比如两个int类型的变量,比较的是变量的值是否一样;

2、引用数据类型:比较的是两个引用对象指向的内存地址是否相同。

二、字符串常量池

Java中字符串对象主要有两种创建方式,第一种是通过”字面量“赋值,例如:String str="HWY";第二种是通过new关键字创建新对象,

例如String str=new String("HWY");这两种创建String对象有什么区别呢?

要讨论这个问题,首先要明白JVM运行时数据区和字符串常量池(String Pool)

方法区:存储类信息、常量、静态变量,全局共享。

堆区:存放对象和数组,全局共享。

栈区:存放基本数据类型、对象的引用,线程私有。

创建字符串对象主要与方法区、堆区和栈区有关,最相关的是字符串池(String Pool),其位置在jdk1.7之后移动到堆中。

这样我们再回到之前的问题,通过”字面量“赋值,例如:String str="HWY"创建字符串对象时,会在字符串常量池中创建“HWY”的对象,并

存放一个它的引用。此时类并没有加载完成,main方法中还没有创建str,当main方法执行到String str="HWY"时,虚拟机会去字符串池中找是否

有equals(“HWY”)的String,然后把在字符串池中“HWY”的引用复制给str。

当通过new关键字创建新对象,例如String str=new String("HWY")时,无论字符串常量池中是否有equals(“HWY”)的String,都会在堆中开辟一

块新的内存地址,存放一个字符串对象“HWY”,并在常量池中存放该对象的引用(如果发现常量池中已经有了字符串常量“HWY”,就不会再去创建),此时str指向的是堆

中字符串对象的地址。

三、字符串判等解析

了解完两种不同方式创建字符串对象的区别之后,可以看一下以下几个例子:

例1:

 

 输出结果为:

这是比较常见的字符串比较问题,输出结果为false。解析:String s1="HHH",会在字符串常量池中存放一个内容为“HHH”的String对象的引用,并将该引用赋值给s1,

new关键字在堆中创建了一个新的字符串对象,s2指向的该字符串对象在堆中的地址,s2与s1指向的是不同的地址,因而输出false。

例2:

 

输出结果为:

解析:对于直接做+运算的两个字符串(字面量)对象,并不会放入字符串常量池中,而是直接把运算后的结果放入字符串常量池中
(String s 1= "HE"+ "LLO", 会直接生成字面量为“HELLO"字符串对象 ,s1指向的字符串常量池中“HELLO”的引用, 此时s1==s5为true,

String s4=s2+s3;这句被Java编译器做了优化, 实际上使用StringBuilder调用append方法拼接字符串,再调用toString方法返回String对象实现的,

本质上也是在堆中开辟了新的内存空间,此时s4指向的是堆中新创建的字符串对象地址,因而s1==s4为false。

例3:

 

 输出结果为:

解析:这里涉及到intern()方法的使用,当调用 intern 方法时,如果字符串常量池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),

则返回池中的字符串的引用。否则,将此 String 对象添加到池中,将堆中String对象的引用复制给字符串常量池中,并返回此 String 对象的引用(堆中)。

当s2调用intern()方法时,字符串常量池中已经存在“HWY”字符串,因而直接返回字符串常量池该字符串的引用,所以s2.intern()==s1为true;

对于String s3=new String("中南")+new String("大学");此时会在堆中创建3个对象“中南”、“大学”、“中南大学”,而在字符串常量池中只有“中南”、“大学”两个字符串的引用,

因为我没有明确new("中南大学"),所以在字符串常量池中并没有“中南大学”字符串的引用,此时s3调用intern()方法会将堆中“中南大学”字符串对象的地址复制到字符串

常量池中,然后返回堆中“中南大学”的地址,所以此时s4、s3、s3.intern()的引用地址都相同。

以上内容就是关于Java字符串常量池及字符串判等的总结。

 
posted on 2021-04-18 02:37  Simpleeee  阅读(472)  评论(0编辑  收藏  举报