每个代码款中内容都是单独的,没有上下文关系
new String
new必会在堆中开辟空间创建对象
String str1 = “abc”;最多创建一个String对象,最少不创建String对象。
如果常量池中,已经存在“abc”,那么str1直接引用,此时不创建String对象,否则,先在常量池先创建“abc”,再引用。
String str2 = new string(“ABCD”);最多创建两个String对象,至少创建一个String对象。
// 每次new String时都要先在常量池中寻找
// 创建两个对象 先在字符串常量池中创建abc,再在堆中对象指向常量池中
String abc = new String("abc");
// 字符串常量池已有abc,仅在堆中创建对象,让其指向abc
String d = new String("abc");
// 结果false
System.out.println(abc==d);
// 创建五个对象 常量池中a,b ,堆中指向常量池的两个对象,存储ab的对象
String s = new String("a")+new String("b");
// 创建两个对象,字符串常量池中ab,堆中对象,指向ab 不单独创建a和b
String s = new String("a" + "b");
// 仅在常量池中创建ab 不单独创建a和b
String s= "a"+"b";
字面量相加与字符量相加
结果 false true
字面变量赋值在常量池中
字符变量相加在堆空间中开辟空间 ,(实际使用的是StringBuilder.append(s1).apeend(s2)),堆中对象存储abc,常量池中无abc(new对象情况下仅堆中对象仅存储常量池引用)
字面常量相加在常量池中开辟空间,且仅在常量池中存储结果
故s3,s4指向地址不同
因"abcxyz"已存在常量池中,s5直接指向这个地址,s4,s5地址相同
true true(JDK1.8之后)false true(JDK1.7之前)
intern方法
如果长量池中存在,则直接返回常量池对象引用
JDK1.6之前:如果常量池中没有,就把对象复制一份放到常量池中,返回****常量池中对象的引用
JDK1.7之后用如果常量池中没有,就把对象引用复制到常量池中,返回****常量池中的对象引用(这个引用是指向常量池外的对象的),
也说明字符串常量中不止存在字符串,还存在引用,
这里说1.7之后:
s3地址指向堆中“abcxyz”,调用intern()后,由于常量池中没有,把对象引用(“s3中地址”)放到常量池中,把地址赋值返回给s4(并不是指向这个地址,要是指向,肯定是false,JDK1.6之前是把堆中值复制过去,s4指向常量池,故是false),故s3,s4相同
true
特殊
false
java等一些特殊字符已经在常量池中,intern会直接返回常量池中地址,而s3是指向堆中的
扩展
final String s1="a ";
final String s2="b";
String s3="a b";
String s4=s6+s7;
System.out.println(s8=s9);
结果true
s3,s4都是引用#4 故相等
String s=new String("a")+new String("b");
// 反编译实际执行了
String s2 = (new StringBuilder()).append(new String("a")).append(new String("b")).toString();
共创建了6个对象,常量池的 a,b;堆中的StringBuilder对象,a,b对象,以及toString方法产生的一个对象(不会再常量池中创建对象),s是指向这个toString方法创建的对象
// StringBuilder赋值给String对象,会调用此方法
public String toString() {
// Create a copy, don't share the array
// 但此种构造方法不会在常量池创创建ab对象
return new String(value, 0, count);
}
intern详解
如果长量池中存在,则直接返回常量池对象引用
JDK1.6之前:如果常量池中没有,就把对象复制一份放到常量池中,返回****常量池中对象的引用
JDK1.7之后用如果常量池中没有,就把对象引用复制到常量池中,返回 常量池中的对象引用(这个引用是指向常量池外的对象的)
以下仅解释1.7之后的,
String s= new String("ab");
String intern = s.intern();
System.out.println(intern==s);
1.6 1.7 false
第一行会创建两个对象,堆中一个,String Pool中一个,第二行发现常量池中已存在,则直接返回ab对象地址,s指向堆,intern指向 常量池
String s1= "abc";
String s2= "xyz";
String s = s1 + s2;
System.out.println(s==s.intern());
s.intern()会返回指向肚子红abcxyz的引用
String s=new String("a")+new String("b");
s.intern();
String s1="ab";
System.out.println(s==s1);
第二行将堆中ab的引用放入常量池,s1赋值时从常量池中发现堆中已有ab,则直接将这个引用赋值给s1
字符串赋值字面量时,会先从常量池中查找有没有,如果有则直接返回,没有时才创建,这个查找包括 字符串常量 和 intern放入的引用