关于String在内存中的存储问题

img

如图,s3,s4,s5都是不同的内存地址且s3在字符串常量池我可以理解
想请问一下,那s4 和 s5 是怎么在内存中储存的呢?
或者说,执行到第4,5行的时候 内存中是怎么样的一个过程呢?

s4=s1+"world";因为右侧表达式s1不是常量,所以s4不会从常量池中查找是否有这个字符,而是重新申请一块空间来存储相加的结果;同理,s5也是一个道理。

我们先来说说基本数据类型:
在Java中有boolean,byte short int long double float short,然后
string不属于基本数据类型,这个时候就出现了怎么存数据的问题
string,你定义了一个字符串那他就会把字符串存在常量池中。
也就是说
你定义的s1,s2,的hello world是在字符串常量池中,s1,s2在栈中存的都是指向常量池的地址

而s3执行时候,虽然是+但是在jvm的优化下,会采用先stringbuilder的方式进行字符串想加,然后toString形成新的字符串在堆中存起来,这个时候s3,在栈中存的地址就指向helloworld,
之后你的你的s4=s1+world,虽然s1是hello,但是他在栈中存的事地址,他需要先去找到地址,然后再去地址中找到值之后想加,想加之后形成的值,又存在一个新的地方。

而s5也是同样,他是先找到s1s2中的地址,然后去内存中找对应的值,然后去堆中继续存储起来
然后你还要明白一点是
==比较的是内存地址,而字符串比较值使用equars
你还要明白的第一地方
s1,s2,是存在字符串常量池中,是常量
s3 s4 s5是直接存在堆中是个对象

所以这个时候当你s3/s4/s5,无论怎么比较都是false

(手机打的不容易,排版差了点,听懂了满意了给个采纳吧)


  0 ldc #7 <hello>
  2 astore_1
  3 ldc #9 <world>
  5 astore_2
  6 ldc #11 <helloworld>
  8 astore_3
  9 new #13 <java/lang/StringBuilder>
 12 dup
 13 invokespecial #15 <java/lang/StringBuilder.<init> : ()V>
 16 aload_1
 17 invokevirtual #16 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
 20 ldc #9 <world>
 22 invokevirtual #16 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
 25 invokevirtual #20 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
 28 astore 4
 30 new #13 <java/lang/StringBuilder>
 33 dup
 34 invokespecial #15 <java/lang/StringBuilder.<init> : ()V>
 37 aload_1
 38 invokevirtual #16 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
 41 aload_2
 42 invokevirtual #16 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
 45 invokevirtual #20 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
 48 astore 5

上面是用 javap -c -v 查看你写的代码对应的字节码,可以看出 s3 在编译时被 javac 写入常量池了,而 s4s5 都是由 StringBuildertoString 方法得到的。所以结论是:
s1 s2 s3 在常量池;
s4 s5 是在堆里的。