1 String对象存放位置
1) 直接指定内容的String对象存放在字符串常量池中
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // true
s2直接指向s1的内存地址,两者共用同一个字符串,都在常量池中
2) 只有使用引号包含文本方式创建的String对象之间使用"+"链接产生的新对象才会被加入到字符串池中,其他的要在堆中创建
即只有常量用"+"连接才放入字符串池中
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;
System.out.println(s1 == s9); // false
s7,s8在字符串常量池中创建,s9在堆中创建
3)在 Java中,使用 new创建的对象,都存放在堆中
String s4 = "Hel" + new String("lo");
2 特例
- 特例1
public static final String A = "ab"; // 常量A
public static final String B = "cd"; // 常量B
public static void main(String[] args) {
String s = A + B; // 将两个常量用+连接对s进行初始化
String t = "abcd";
if (s == t) {
System.out.println("s等于t,它们是同一个对象");
} else {
System.out.println("s不等于t,它们不是同一个对象");
}
}
s等于t,它们是同一个对象
A和B都是常量,值是固定的,因此s的值也是固定的,它在类被编译时就已经确定了。也就是说:String s=A+B; 等同于:String s=“ab”+“cd”;
- 特例2
public static final String A; // 常量A
public static final String B; // 常量B
static {
A = "ab";
B = "cd";
}
public static void main(String[] args) {
// 将两个常量用+连接对s进行初始化
String s = A + B;
String t = "abcd";
if (s == t) {
System.out.println("s等于t,它们是同一个对象");
} else {
System.out.println("s不等于t,它们不是同一个对象");
}
}
s不等于t,它们不是同一个对象
A和B虽然被定义为常量,但是它们都没有马上被赋值。在运算出s的值之前,他们何时被赋值,以及被赋予什么样的值,都是个变数。因此A和B在被赋值之前,性质类似于一个变量。那么s就不能在编译期被确定,而只能在运行时被创建了
3 总结
- 必须要关注编译期的行为,才能更好的理解常量池
- 运行时常量池中的常量,基本来源于各个class文件中的常量池
- 程序运行时,除非手动向常量池中添加常量(比如调用intern方法),否则jvm不会自动添加常量到常量池