String 对象可谓再熟悉不过了,与此相关的面试题经常会引出内存性能优化的问题,本篇主要以 new String("123") 创建了几个对象为例记录。
String a = "123";
如上定义的为常量;
String b = a +"456";
如上 b 为变量,为啥? 难道常量拼接常量得到的是变量吗?
不是,常量拼接常量得到的依旧是常量。
但是此时将 a 作为引用,a 已经不再是常量了,是变量了,所以得到的 b 自然就是变量。
String b = "123" + "456";
此时 b 为常量。
如果给 a 加上修饰符 final ,那么 a 就是个常量,那么 b 就为常量了。
我们再来通过两种写法分析:
String a = "123";
String b = new String("123");
如上第1行,定义了一个常量 a ,第2行,通过关键字 new 的形式,创建了一个变量 b 。
我们结合之前学过的 JVm 再深入一些,第1行在常量池开辟了一块空间,存放字符串 123,通过 a 对象指向这个常量对象。第2行由于使用了 new 关键字,所以会在堆空间中开辟一块内存区域,在其中存放字符串 123,并把内存的地址赋予 b 变量。
所以, a==b 吗?显示是 false,一个是堆内存,一个是常量池。
如果将 a 修改成:
String a = new String("123");
那么,a==b 吗?
依旧是 false。
为什么?只要通过 new 形式,自然是创建两个对象,所以是 false,即便是他们的值是一致的。
String 常量存放在常量池中,jvm处于优化考虑,会让内容一致的对象共享内存块,但变量是放在堆空间中的,new 定义的不同变量内存地址不同。
String 常量连接常量,还是常量,依旧用常量池管理,但常量连接变量就是变量了。
以下几种情况(均不考虑字符串在常量池中已存在的情况):
创建了1个对象
jvm在编译阶段会判断常量池中是否有 "123" 这个常量对象如果有,a直接指向这个常量的引用,如果没有会在常量池里创建这个常量对象。
创建了2个对象
同情况1,jvm编译阶段判断常量池中 "123"存在与否,进而来判断是否创建常量对象,然后运行阶段通过new关键字在java heap创建String对象。
创建了1个对象
jvm编译阶段过编译器优化后会把字符串常量直接合并成"123456",所有创建对象时最多会在常量池中创建1个对象。
创建了4个对象
常量池对象"123" ,"456",new String("456")创建堆对象,还有一个堆对象"123456"。
最后练习参考文章:https://blog.csdn.net/baidu_27969827/article/details/79219708
原文:https://www.cnblogs.com/niceyoo/p/11100090.html