赶时间的请直接跳到习题解释:
一、题目
画出如下几行代码的内存(堆栈)结构:
String s1 = “hello”;
String s2 = “hello”;
String s3 = new String(“hello”);
s1 += “world”;
第一行:为s1赋值,在常量池中找hello,没找到,创建hello,并把hello的地址赋给s1
第二行:为s2赋值,在常量池中找hello,找到了,把hello地址赋给s1
第三行:new一个s3对象,并在堆内存中开辟一个空间存储hello
第四行:字符串相加,s1不再是常量,地址改变
二、解释
1、常量池知识扩展
JDK1.6及以前,常量池所处位置在方法区中,此时的方法区也叫做永久代
JDK1.7,方法区合并到堆内存中,此时常量池所处位置为堆内存
JDK1.8及以后,方法区从堆内存中剥离出来,此时的方法区叫做元空间,此时的常量池就在元空间中
2、那么什么是常量池呢
常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。
可以理解为class文件之中的资源仓库,它是class文件结构中与其他项目关联最多的数据类型,也是占用class文件空间最大的数据项目之一,同时它还是class文件中第一个出现表类型的数据项目。
3、java中的intern()方法
当调用 intern 方法时,如果池中已经包含一个与该方法确定的对象相等的字符串,则返回池中的字符串。 否则,将此对象添加到池 中并返回对该对象的引用。) 翻译过来的意思就是:如果常量池中已经有了此字符串,那么将常量池中该字符串的引用返回,如果没有,那么将该字符串对象添加到常量池中,并且将引用返回(结果:一个字符串与该字符串具有相同的内容,但保证来自一个唯一的字符串池。 )。 首先要明白,这里注释的该字符串是调用此方法的字符串,返回的是引用。
//后面发现此知识点与习题解释无关,纯粹扩展
3、习题解释
一二三行的代码大家应该也没有疑问,主要是第四行,它的地址在哪里呢,这也是我疑问,于是,我做了实验
String一个跟s1相同字符串的常量,然后跟s1做比较,如果s1还在常量池中,他们应该是等的
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
s1 +="world";
String s4="helloworld";
System.out.println(s1==s4);
System.out.println(s1.equals(s4));
这里用了==和equals()来比较(==比较的是值和地址,equals比较的是值)
结果为
由此可见,s1已经不在常量池中了,至于在不在堆内存中,由于知识受限,我不能确定。