引言
Java语言不要求常量一定要在编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区的运行时常量池,程序运行期间也可以将常量放入池中。
设计字符串常量池的原因
字符串在java程序中被大量使用,为了避免每次都创建相同的字符串对象及内存分配,JVM内部对字符串对象的创建做了一定的优化,在Permanent Generation中专门有一块区域用来存储字符串常量池(一组指针指向Heap中的String对象的内存地址)。
字符串所在的内存区域
两种内存区域:常量池、堆
String str1 = "helloworld"; //存在于常量池中 String str2 = new String("helloworld"); // 'helloworld'存在于常量池中,String对象存在于堆中 String str3 = str1 + "world"; // 有字符串引用时,在堆中建立一个String对象将引用返回
String中intern的方法
当调用 intern 方法时,如果池已经包含一个等于此String对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并且返回此 String对象的引用。
public static void main(String[] args) { String str1 = "a"; String str2 = "b"; String str3 = "ab"; String str4 = str1 + str2; String str5 = new String("ab"); System.out.println(str5 == str3); System.out.println(str5.intern() == str3); System.out.println(str5.intern() == str4); }
结果:false, true, false
解析原因:1、一个存在于常量池中,一个存在于堆中对象地址不同返回false
2、str5执行intern方法去常量池中判断有没有和''ab''字符串equals的字符串,一看有就是str3返回str3的引用,此时再==时返回true
3、str5执行intern方法去常量池中判断有没有和''ab''字符串equals的字符串,一看有就是str3返回str3的引用,此时判断str3和str4是否==,我们知道str3存在于常量池,str4存在于堆中地址不同返回false
str1,str2,str3在JVM编译期就已经存在了位于字符串常量池中,而str4和str5是在程序运行期才存在的位于堆中