相信不少同学都会看到"String s=new String("abc")共创建了多少个对象"之类的面试题,在此小议一下这个小问题,如有不对,望各位指正。
一、String的两种初始方法
1.String str1=new String("abc");
2.String str2="abc";
这两个方法都可以得到String的对象。
二、两种初始化String方法的区别
执行语句String str1=new String("abc")时,不管"String常量池"中是否存在字符串"abc",直接在堆内存中新建一个字符串"abc",然后将其赋给str1,[b]并且[/b]在"String常量池"中创建"abc",故第一种方法共创建了2个对象(一个在堆内存上,一个在"String常量池"上)和一个引用变量。
执行语句String str2="abc"时,首先查看"String常量池"中是否存在字符串"abc",如果存在则直接将"abc"赋给str2,如果不存在则先[color=red]在"String常量池"中[/color]新建一个字符串"abc",然后再将其赋给str2。
所以两种初始化的方法的区别是第一种方法不仅会在堆内存上建立相应的对象,还会在一块特殊的内存区域建立相应的对象,而第二种方法只在特殊的内存区域("String常量池")建String对象。
三、Java为什么这样设计?
需要知道的是,String对象是不可变的,一旦创建就不能再作任何修改,否则JVM只会帮你创建一个新的且符合你的要求的String对象(不要被假象所迷惑) ,以下做一个小验证:
结果是:a=abc
的确,在执行a.concat("efg")时会返回一个新的String对象,原对象并不会改变。
这样的后果是造成大量的冗余。如上面执行完第二句后,a的依旧引用的是"abc",而新建的一个String对象"abcefg"并没有一个引用变量指向它,这片区域就成垃圾内存了……
SUN把String设计成不可修改,引入"String常量池"是为了高效地使用内存。
一、String的两种初始方法
1.String str1=new String("abc");
2.String str2="abc";
这两个方法都可以得到String的对象。
二、两种初始化String方法的区别
执行语句String str1=new String("abc")时,不管"String常量池"中是否存在字符串"abc",直接在堆内存中新建一个字符串"abc",然后将其赋给str1,[b]并且[/b]在"String常量池"中创建"abc",故第一种方法共创建了2个对象(一个在堆内存上,一个在"String常量池"上)和一个引用变量。
执行语句String str2="abc"时,首先查看"String常量池"中是否存在字符串"abc",如果存在则直接将"abc"赋给str2,如果不存在则先[color=red]在"String常量池"中[/color]新建一个字符串"abc",然后再将其赋给str2。
所以两种初始化的方法的区别是第一种方法不仅会在堆内存上建立相应的对象,还会在一块特殊的内存区域建立相应的对象,而第二种方法只在特殊的内存区域("String常量池")建String对象。
三、Java为什么这样设计?
需要知道的是,String对象是不可变的,一旦创建就不能再作任何修改,否则JVM只会帮你创建一个新的且符合你的要求的String对象(不要被假象所迷惑) ,以下做一个小验证:
String a="abc";
a.concat("efg");
System.out.println("a="+a);
结果是:a=abc
的确,在执行a.concat("efg")时会返回一个新的String对象,原对象并不会改变。
这样的后果是造成大量的冗余。如上面执行完第二句后,a的依旧引用的是"abc",而新建的一个String对象"abcefg"并没有一个引用变量指向它,这片区域就成垃圾内存了……
SUN把String设计成不可修改,引入"String常量池"是为了高效地使用内存。