1:字符串在不同的创建方法时有会有多少个对象呢
(1):String str="abc"+"abc";
答:1个,在字符串常量池创建了一个对象。
(2):String str="qwe",String str=new String("qwe");
答:2个,在字符串常量池里面创建一个,在堆中创建一个
(3):String str="qwe"+new String("qwe");
答:3个,字符串常量中一个,堆中两个,一个是new String("qwe"),一个进行相加的值存入堆中
(4):String str=new String("abc")+new String("abc");
答:4个,字符串常量池1个,堆2个,拼接的那一个存放在堆
(5)String str="qwe"+new String("abc");
答:5个,字符串常量中两个,分别是qwe和abc,堆中也有对应的两个,拼接的那一个也存在堆中
2:字符串的常量池和堆
到这对于字符串创建时的数量有一个简单的认知了,接下来了解一下它们分别什么时候存入常量池,什么时候存入堆的。
对于String这个类型而言,它是一个常量,常量就是不变的,在java中有专门存放常量的地方,也就是常量池,而堆就简单理解为存放对象的地方,在上面的的语句中,假如String str="qwe"它就是将qwe存入字符串常量池,在存入常量池之前会看常量池里面是否有对应的字面值,如果有对应的字面值,就会使用对应的对象,解释一下这个所谓的对应的对象,这个对象是Java在编译时创建的,当编译器遇到这个字面值时,也就是字符串"qwe"时就会去字符串常量池里找对应的字面值,如果存在就会使用与字面值对应的对象,不存在就在常量池中创建一个对象,并将字面值存入其中,所以也就是说在Java常量池中可以理解为存放一个字面值和一个与之对应的对象,这个对象在编译时被创建,在运行时被重用,而new String("qwe")呢,因为在这个语句里面也有个"qwe"字符串,所以在编译时也会进行字符串常量池的查找操作,所以也就是说new String("qwe")执行了两次对象创建,而String str="qwe"只执行了一次创建对象操作。
String str="qwe",String str=new String("qwe");这段语句就很好的解释了以上的内容,假如编译期间String str="qwe"这个时候并没有qwe的对象,如何执行这个语句时就创建了一个qwe的对象,而再次执行String str=new String("qwe")在编译阶段发现已经有一个que的字面值的对象了,就不再创建了,但在运行期间还需要new String("qwe");在堆中创建一个对象,然后它们拼接的新的对象要存在堆中,所以也就是创建了3个对象
3:后续添加内容
后面看到一篇文章,以上在常量池中创建对象是JavaJdk1.6版本才会创建
文章地址:http://t.csdnimg.cn/V8ht3
在Java1.7时不会创建了,因为常量池放在堆中间了,采用在常量池中使用地址引用堆中的对象的方式了,1.6是放在Perm区域,也就是说在1.7对于Java中String来说,创建对象应该整体的少了一个了,因为String str="qwe"在编译时是否还需要在常量池创建对象呢,如果做直接引用的话,为是编译期间,堆里面还没有对应的对象,所以应该引用不了,所以这个时候做了在常量池什么,又或者只针对一部分类型才使用地址引用方法,如果还继续创建对象那么当运行时是否会改变成引用还是直接将对象创建到堆里面,这个我也有点不清楚了。
我问了一下chatgpt:
这是gpt的解释:
在编译期间,如果遇到字符串常量的赋值语句,例如 String str1 = "hello";
,编译器会检查常量池中是否已经存在 "hello"
这个字符串常量。
-
如果常量池中不存在
"hello"
这个字符串常量,编译器会在常量池中创建一个新的字符串常量,并在编译后的字节码中使用该常量的引用。这个引用在字节码中表示为一个索引值,指向常量池中的位置。 -
如果常量池中已经存在
"hello"
这个字符串常量,编译器会直接在编译后的字节码中使用该字符串常量的引用,而不会再创建新的字符串常量。
所以说,编译器并不会在常量池中创建字符串常量并引用它,而是在常量池中查找已有的字符串常量,并在编译后的字节码中使用它的引用。