有了目标,就赶紧行动
注意:每new一个“ab”,就代表堆内存中出现了新的“ab”,但是常量池中只会有一份”ab";
所以这个问题你只需要看懂是堆内存中的还是常量池中的
具体细节参考博客 https://blog.csdn.net/vegetable_bird_001/article/details/51278339
String s1 = "ab" ;//常量池中没有,所以系统在堆内存中申请一份,再放常量池一份,因为没有明显的说new,所以要的是常量池的那一份
String s2 = "ab";//注意这个也没有明显的new,所以他要的是常量池中的那一份,先去常量池中找,常量池中有了,所以说s2和 s1都指向常量池中相同的那一份 “ab”
System.out.println(s1 == s2); //true
String s3 = new String("ab");//有new关键字,所以在堆内存中重新申请了一份“ab" s1是常量池的那一份
System.out.println(s1 == s3);//false
例子1:
String s4 = "a" + "b";//没有new 要的是常量池的那一份
System.out.println(s1 == s4);//true
例子2:
//和第三个代码段做对比
String s5 = "a" ;
String s6 = s5 + "b";//s6在堆内存中重新申请了一份”ab",而s1是常量池的那一份
System.out.println(s1 == s6);//false
解释:你可以看到第一个例子当中String s4 = "a" + "b"
,因为java有常量优化的机制,在把java文件编译成class文件时,这行代码其实变成了String s4 = "ab"
,很明显 s1 = s4共享 "ab" 这个字符串,所以返回true。但是第二个例子可就不是这样了,s5 是一个变量,它指向字符串常量 “a” 。因为变量可以改变指向,那么在编译String s6 = s5 + “b”
的时候 jvm 肯定不会认为String s6 = "ab"
,也就没有共享常量池中的 "ab"
那么一说,所以会为s6 创建一个全新的对象。因此 "ab"
和 s6并不是同一个对象,== 比较自然会返回false。
补充:这里再记录一个常量优化的例子:
byte num1 = 1;
byte num2 = 3;
byte num3 = num1 + num2;
第三行代码对不对那?可以肯定的说,会报错。因为 byte/short/char 类型的数据在进行数学运算的时候 会自动被提升为 int 类型,第三行代码就相当于 byte = int + int。用byte接收int,肯定不行。再看下面这行代码:
byte num= 1 + 2;
我们都知道 整型数据默认就是 int,这行代码难道不相当于byte = int + int 吗?其实不是,因为常量优化机制的存在,在编译成class文件后,这行代码实际上变成了 byte = 3,3 没有超过byte的范围,所以不会报错。如果写byte num= 127 + 1
,超出了 byte范围,那么就会报错。