学习软件构造的过程中,往往会对string这一特殊对象感到好奇,因为它是java自带的引用类型中唯一的immutable类。
前置知识:JDK1.8中JVM把String常量池移入了堆中,同时取消了“永久代”,改用元空间代替(Metaspace)
java中对String对象特殊对待,所以在heap区域分成了两块,一块是字符串常量池(String constant pool),用于存储java字符串常量对象,另一块用于存储普通对象及字符串对象。
声明一个string的时候有两种办法,一个是编辑器里面直接以文本形式双括号声明,一个是new一个出来。
String a = "abc";
String b = new String("abc");
String c = "abc";
System.out.println(a == b);//false
System.out.println(a == c);//true
第一种方案中,字符串储存在常量池里,在使用这种方法重复创建一样的字符串的时候,java会先在字符串池中进行检索,这样声明出来的、相同的字符串引用就在代码运行时在常量池里面指向同一块空间。首先在String constant pool 中寻找是否已经存在"abc"常量,如果没有则创建该常量,并且将此常量的引用返回给String a;如果已有"abc" 常量,则直接返回String constant pool 中“abc” 的引用给String a。
第二种方案,字符串储存在堆里,因此直接使用==判断是否相等是不可行的,应当使用equals方法。凡是使用new动态创建的string对象都是在堆里面。
使用第二种方案创建的字符串,可以通过intern方法,在字符串池中创建一个字符串,这时候流程按照第一种。如果在字符串池中匹配到已存在一个相同的字符串序列,java会直接将intern方法返回的引用指向已存在的那块空间。
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2); //false
System.out.println(s1.intern() == s2); //true
例子:
String s1 = "abc";//字符串池
String s2 = "xyz";//字符串池
String s3 = "123";//字符串池
String s4 = "A";//字符串池
String s5 = new String("abc"); //堆
char[] c = {'J','A','V','A'};
String s6 = new String(c);//堆
String s7 = new String(new StringBuffer());//堆
所以使用equals方法判断的时候,在堆里面可以有多个equals的字符串对象,但是在字符串池中只有一个。



