public class text{
public static void main(string[] args){
string s1 = "java";
string s2 = "java";
string s3 = new string("java");
system.out.println(s1==s2);//true
system.out.println(s1 == s3);//false
system.out.println(s1.equals(s3));//true仔细看这段代码,明明三个字符串的内容都是java,运行结果却不相同,核心原因在于java字符串常量池的存在,以及==和equal的本质区别。
一、java字符串常量池
为了提升程序性能,减少内存开销,java专门开辟了一块字符串常量池(string constant pool),它是属于方法区的一部分,是专门用于储存字符串常量的缓存区域。
它的核心规则是:
1,当使用双引号“”直接赋值创建字符串时,jvm会先去字符串常量池中检查,是否已经存在相同内容的字符串;
2,如果常量池中已经存在,直接返回常量池中该字符串的内存地址,否则,在常量池中创建新对象,再返回其地址;
二、new string 创建对象的底层逻辑
当使用new string("java")创建字符串时,执行逻辑完全不同,jvm会做两件事:
1,先去字符串常量池中检查是否存在java,不存在则在池中创建;
2,在堆内存中重新开辟一个新的内存空间,创建一个新的string对象,堆中对象的内容指向常量池中的java字符串;
3,最终变量s3储存的是堆内存中新建对象的地址,而非常量池的地址。
三、==和equal的本质区别
(1)“==”运算符
1,对于基本数据类型比较的是变量的值。
2,对于引用数据类型比较的是对象的内存地址,而非内容。
(2)equals()方法
1,equal方法是object类中的方法,string类对其进行了重写。
2,string重写后的equal方法,会逐字符比较两个字符串的内容是否完全一致,和内存地址无关。
四、其他常见错误
(1)字符串拼接的常量池陷阱
string s1 = "hello"; string s2 = "world"; string s3 = "helloworld" string s4 = "hello"+"world"; string s5 = s1 + s2; system.out.println(s3==s4);//true system.out.println(s3==s5);//false
原因:
- 常量拼接会在编译期直接优化为完整字符串,存入常量池;
- 变量拼接底层通过stringbuilder实现,最终生成的对象在堆内存,地址和常量池不同。
(2)null值调用equals的空指针问题
string s1 = null; string s2 = "java"; system.out.println(s1.equal(s2));//会抛出nullpointerexception system.out.println(s2.equal.(s1))
所以在做字符串判等时,用已知的常量字符串调用equals方法,避免空指针异常。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论